ServiceNow Security ログを収集する
このドキュメントでは、Webhook フィードを使用して ServiceNow セキュリティ イベントを Google Security Operations に送信する方法について説明します。ServiceNow Security パーサーは、ログインの失敗、SNC ログイン、管理者ログイン、権限借用、セキュリティ昇格などの ServiceNow Instance Security Center セキュリティ イベント用に設計されています(ServiceNow Instance Security Center セキュリティ イベントをご覧ください)。ServiceNow 統合は、各イベントを JSON として Google SecOps Webhook エンドポイントに投稿します。ここで、パーサーはイベントを Unified Data Model(UDM)に正規化します。
パーサーは、Failed Login、Admin Login、SNC Login、Impersonation、Security Elevation の 5 つのイベント値を認識します。各値は、sysevent キューに登録された ServiceNow イベントに対応しています。このドキュメントでは、Webhook フィード、フィードに POST するスクリプト インクルード、一致する sysevent レコードでトリガーされ、スクリプト インクルードを呼び出す 4 つのスクリプト アクションを作成します。
この 1 回限りの設定を行うと、ServiceNow は新しいセキュリティ イベントを Google SecOps に自動的に転送します。管理者による対応は不要です。
始める前に
次の前提条件を満たしていることを確認します。
- Google SecOps インスタンス。
adminロールを持つユーザー アカウント、または [System Definition] > [Script Includes]、[System Properties]、[System Policy] > [Events] > [Script Actions]、[Registry] への権限を持つユーザー アカウントがある ServiceNow インスタンス。- 既存の ServiceNow インスタンス セキュリティ センターの有効化。ISC は販売終了しており、新しいインスタンスで有効にすることはできません。
- Google Google Cloud コンソールへの特権アクセス(API キーの作成用)。
Google SecOps で Webhook フィードを作成する
以降のセクションでは、Google SecOps で Webhook フィードを作成する方法について説明します。
フィードを作成する
- [SIEM 設定] > [フィード] に移動します。
- [Add New Feed] をクリックします。
- 次のページで、[単一のフィードを設定] をクリックします。
- [フィード名] フィールドに、フィードの名前を入力します(例:
ServiceNow Security Events)。 - [Source type] として [Webhook] を選択します。
- [ログタイプ] として [ServiceNow Security] を選択します。
- [次へ] をクリックします。
次の入力パラメータの値を指定します。
- 分割区切り文字: 統合がリクエストごとに複数の JSON イベントを送信する場合は、
\nを入力します。各リクエストに 1 つのイベントが含まれている場合は、空のままにします。 - Asset namespace: アセットの名前空間。
- Ingestion labels: このフィードのイベントに適用されるラベル。
- 分割区切り文字: 統合がリクエストごとに複数の JSON イベントを送信する場合は、
[次へ] をクリックします。
[Finalize] 画面で新しいフィードの設定を確認し、[送信] をクリックします。
秘密鍵を生成して保存する
- フィードの詳細ページで、[シークレット キーを生成] をクリックします。
秘密鍵をコピーして安全な場所に保存します。
フィード エンドポイントの URL を取得する
- フィードの [詳細] タブに移動します。
[エンドポイント情報] セクションで、[フィード エンドポイント URL] をコピーします。URL の形式は次のとおりです。
https://malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreateリージョン エンドポイントの場合:
https://<REGION>-malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreateこの URL は後の手順で使用するため、保存しておきます。
[完了] をクリックします。
Google Cloud API キーを作成する
- Google Google Cloud コンソールの [認証情報] ページに移動します。
- Google SecOps インスタンスに関連付けられているプロジェクトを選択します。
- [認証情報を作成> API キー] をクリックします。
- [API キーを編集] をクリックして、キーを制限します。
- [名前] フィールドに、わかりやすい名前(例:
ServiceNow Webhook API Key)を入力します。 [API の制限] で次の操作を行います。
- [キーを制限] を選択します。
- [API を選択] リストで、[Google SecOps API] を選択します。
[保存] をクリックします。
API キーをコピーして、安全な場所に保存します。
Google SecOps の認証情報を ServiceNow に保存する
統合コードにシークレットが含まれないように、エンドポイント URL と認証情報を ServiceNow システム プロパティとして保存します。
- ServiceNow で、[System Properties] > sys_properties.list に移動します。
[新規] をクリックして、次の構成の詳細を指定します。
- 名前:
x_chronicle.endpoint_url - 値: フィード エンドポイント URL を貼り付けます。
- タイプ:
string
- 名前:
[送信] をクリックします。
[新規] をクリックして、次の構成の詳細を指定します。
- 名前:
x_chronicle.api_key - 値: Google Cloud API キーを貼り付けます。
- タイプ:
password2
- 名前:
[送信] をクリックします。
[新規] をクリックして、次の構成の詳細を指定します。
- 名前:
x_chronicle.secret_key - 値: Google SecOps フィードの秘密鍵を貼り付けます。
- タイプ:
password2
- 名前:
[送信] をクリックします。
Webhook ユーティリティのスクリプト インクルードを作成する
このスクリプト インクルードは、ServiceNow sn_ws.RESTMessageV2 スコープ API を使用して、JSON ペイロードを Google SecOps Webhook エンドポイントに投稿します。API キーとシークレット キーは HTTP ヘッダーとして送信されます。
- [System Definition> Script Includes] に移動します。
- [New] をクリックします。
次の構成情報を提供してください。
- 名前:
ChronicleWebhookUtil - API 名:
ChronicleWebhookUtil - Client callable: チェックを外します
- 有効: チェックボックスをオンにする
- 名前:
[スクリプト] フィールドに次のコードを入力します。
var ChronicleWebhookUtil = Class.create(); ChronicleWebhookUtil.prototype = { initialize: function() { this.endpointURL = gs.getProperty('x_chronicle.endpoint_url'); this.apiKey = gs.getProperty('x_chronicle.api_key'); this.secretKey = gs.getProperty('x_chronicle.secret_key'); }, // payload: a plain object whose keys match the required JSON contract. sendEvent: function(payload) { try { if (!this.endpointURL || !this.apiKey || !this.secretKey) { gs.error('[Chronicle] Missing configuration. Check System Properties: x_chronicle.*'); return false; } var request = new sn_ws.RESTMessageV2(); request.setEndpoint(this.endpointURL); request.setHttpMethod('POST'); request.setRequestHeader('Content-Type', 'application/json'); request.setRequestHeader('X-goog-api-key', this.apiKey); request.setRequestHeader('X-Webhook-Access-Key', this.secretKey); request.setRequestBody(JSON.stringify(payload)); var response = request.execute(); var statusCode = response.getStatusCode(); if (statusCode == 200 || statusCode == 201 || statusCode == 204) { gs.info('[Chronicle] Event sent: ' + payload.event + ' | Status: ' + statusCode); return true; } gs.error('[Chronicle] Failed to send event: ' + payload.event + ' | Status: ' + statusCode + ' | Response: ' + response.getBody()); return false; } catch (ex) { gs.error('[Chronicle] Exception sending event: ' + ex.message); return false; } }, type: 'ChronicleWebhookUtil' };[送信] をクリックします。
イベント レジストリを確認する
スクリプト アクションは、イベント名がイベント レジストリ(sysevent_register テーブル)に存在する場合にのみ実行されます。ServiceNow は、この統合で使用される 5 つのイベントをすぐに使用できる状態で提供していますが、エントリが欠落しているとエラーが発生せず、スクリプト アクションが実行されないため、確認することをおすすめします。
- ServiceNow で、[System Policy](
sysevent_register.list)に移動します。 [イベント名] 列で次の各エントリをフィルタし、レコードが存在することを確認します。
loginlogin.failedimpersonation.startsecurity.elevated_role.enabled
エントリがない場合は、[新規] をクリックし、[イベント名] フィールドにない値を設定し、[テーブル] を
Global [global]に設定して、[送信] をクリックします。
スクリプト アクションを作成する
各スクリプト アクションは、1 つの ServiceNow イベント名をサブスクライブします。ServiceNow が一致するレコードを sysevent キューに挿入すると、スクリプト アクションが実行され、イベント パラメータが読み取られ、ChronicleWebhookUtil が呼び出されてペイロードが POST されます。
パーサーは次の ServiceNow イベントにマッピングします。
パーサーの event 値 |
ServiceNow イベント名 | トリガー |
|---|---|---|
Failed Login |
login.failed |
ログイン試行の失敗(任意の認証方法)。 |
Admin Login |
login |
admin ロールを持つユーザーによるログインの成功。 |
SNC Login |
login |
snc_external ロールを持つユーザーによるログインの成功。 |
Impersonation |
impersonation.start |
管理者が別のユーザーになりすまします。 |
Security Elevation |
security.elevated_role.enabled |
ユーザーが security_admin または別の高権限ロールに昇格する。 |
login と login.failed は、parm1 をユーザー名に、parm2 を送信元 IP に設定します。他のイベントも同じ parm1/parm2 の規則に従いますが、正確な内容は ServiceNow のリリースによって異なります。各イベントのレジストリ エントリを開き、パラメータの説明が後述のスクリプトと一致していることを確認します。レジストリが異なる場合は、parm1 または parm2 の参照を調整します。
ログイン失敗スクリプト アクションを作成する
- [System Policy] > [Events] > [Script Actions] に移動します。
- [New] をクリックします。
次の構成情報を提供してください。
- 名前:
Chronicle - Failed Login - イベント名:
login.failed - 有効: チェックボックスをオンにする
- 名前:
[スクリプト] フィールドに次のコードを入力します。
(function runAction(/*GlideRecord*/ current, /*GlideRecord*/ event) { new ChronicleWebhookUtil().sendEvent({ event: 'Failed Login', event_created: event.sys_created_on.getValue(), user: event.parm1.toString(), ip_address: event.parm2.toString() }); })(current, event);[送信] をクリックします。
ログイン スクリプト アクションを作成する
このスクリプト アクションは、ログインが成功するたびに実行され、ログインしたユーザーが admin または snc_external のロールを持っている場合にのみレコードを転送します。event フィールドが適切に設定されます。
- [System Policy] > [Events] > [Script Actions] に移動します。
- [New] をクリックします。
次の構成情報を提供してください。
- 名前:
Chronicle - Login - イベント名:
login - 有効: チェックボックスをオンにする
- 名前:
[スクリプト] フィールドに次のコードを入力します。
(function runAction(/*GlideRecord*/ current, /*GlideRecord*/ event) { var userName = event.parm1.toString(); var ipAddress = event.parm2.toString(); var user = new GlideRecord('sys_user'); if (!user.get('user_name', userName)) { return; } function hasRole(roleName) { var role = new GlideRecord('sys_user_has_role'); role.addQuery('user', user.sys_id); role.addQuery('role.name', roleName); role.query(); return role.next(); } var eventValue; if (hasRole('snc_external')) { eventValue = 'SNC Login'; } else if (hasRole('admin')) { eventValue = 'Admin Login'; } else { return; } new ChronicleWebhookUtil().sendEvent({ event: eventValue, event_created: event.sys_created_on.getValue(), user: userName, ip_address: ipAddress }); })(current, event);[送信] をクリックします。
なりすましスクリプト アクションを作成する
- [System Policy] > [Events] > [Script Actions] に移動します。
- [New] をクリックします。
次の構成情報を提供してください。
- 名前:
Chronicle - Impersonation - イベント名:
impersonation.start - 有効: チェックボックスをオンにする
- 名前:
[スクリプト] フィールドに次のコードを入力します。
(function runAction(/*GlideRecord*/ current, /*GlideRecord*/ event) { new ChronicleWebhookUtil().sendEvent({ event: 'Impersonation', event_created: event.sys_created_on.getValue(), user: event.parm1.toString(), // impersonator snc_user: event.parm2.toString() // impersonated user }); })(current, event);[送信] をクリックします。
セキュリティ昇格スクリプト アクションを作成する
- [System Policy] > [Events] > [Script Actions] に移動します。
- [New] をクリックします。
次の構成情報を提供してください。
- 名前:
Chronicle - Security Elevation - イベント名:
security.elevated_role.enabled - 有効: チェックボックスをオンにする
- 名前:
[スクリプト] フィールドに次のコードを入力します。
(function runAction(/*GlideRecord*/ current, /*GlideRecord*/ event) { new ChronicleWebhookUtil().sendEvent({ event: 'Security Elevation', event_created: event.sys_created_on.getValue(), user: event.parm1.toString() }); })(current, event);[送信] をクリックします。
統合を確認する
次のいずれかの方法を使用します。
合成イベントで検証する
実際のセキュリティ イベントを待たずに各スクリプト アクションをすぐにテストするには、バックグラウンド スクリプトからイベントをキューに登録します。
- ServiceNow で、[System Definition] > [Scripts - Background] に移動します。
[スクリプトを実行] フィールドに次のいずれかの行を入力し、[スクリプトを実行] をクリックします。
gs.eventQueue('login.failed', null, 'test.user', '203.0.113.45'); gs.eventQueue('login', null, 'admin', '203.0.113.45'); gs.eventQueue('impersonation.start', null, 'admin', 'test.user'); gs.eventQueue('security.elevated_role.enabled', null, 'admin', 'security_admin');Event Manager ジョブがキューを処理するまで 1 分ほど待ちます。
実際のイベントで確認する
統合を確認するには、ServiceNow で次のいずれかのマッピングされたセキュリティ イベントを生成します。
- ログイン失敗: プライベート ブラウザ ウィンドウで
/login.doを開き、無効なパスワードを送信します。 - 管理者ログイン: 通常とは異なる IP アドレスから
adminロールを持つユーザーでログインします。 - 権限借用: 管理者アカウントから別のユーザーの権限を借用します。
- セキュリティの昇格:
adminロールを持つユーザーからsecurity_adminロールに昇格します。
転送を確認する
- ServiceNow で、[System Policy] > [Events] > [Event Log](
sysevent.list)に移動し、対応するイベント名を含むレコードが表示されることを確認します。 - ServiceNow で、[System Logs > System Log > All] に移動し、ステータス 200、201、または 204 の
[Chronicle] Event sent: ...情報メッセージが表示されることを確認します。[Chronicle] Failed to send eventまたは[Chronicle] Exception sending eventメッセージは、認証情報または接続の問題を示します。 - Google SecOps で、
metadata.vendor_name = "SERVICENOW"とmetadata.product_name = "SERVICENOW_SECURITY"の UDM 検索を実行します。 - イベントが表示され、
metadata.event_typeがUSER_LOGINまたはUSER_CHANGE_PERMISSIONSに設定され、principal.user.useridが入力されていることを確認します。
認証方法のリファレンス
Google SecOps Webhook フィードは、API キーとシークレット キーを HTTP ヘッダーまたは URL クエリ パラメータとして受け入れます。このガイドでは、ヘッダー メソッドを使用します。これは、sn_ws.RESTMessageV2 がカスタム ヘッダーをサポートしているため、認証情報が URL やサーバー アクセスログに記録されないためです。
このガイドで使用されているヘッダー:
X-goog-api-key: Google SecOps API の Google Cloud API キー。X-Webhook-Access-Key: Google SecOps によって生成されたフィードの秘密鍵。
統合でカスタム ヘッダーを送信できない場合は、代わりにエンドポイント URL に認証情報を追加します。
<ENDPOINT_URL>?key=<API_KEY>&secret=<SECRET_KEY>
Webhook の上限とベスト プラクティス
| 上限 | 値 |
|---|---|
| 最大リクエスト サイズ | 4 MB |
| 最大 QPS(秒間クエリ数) | 15,000 |
| リクエストのタイムアウト | 30 秒 |
| 再試行の動作 | 指数バックオフによる自動 |
ボリュームを制御するには、検出に必要なセキュリティ イベントのみを送信します。ソースがバーストでイベントを生成する場合は、\n 分割区切り文字を使用して、リクエストごとに複数のイベントをバッチ処理します。
Google SecOps フィードの詳細については、Google SecOps フィードのドキュメントをご覧ください。各フィードタイプの要件については、タイプ別のフィード構成をご覧ください。
フィードの作成時に問題が発生した場合は、Google SecOps サポートにお問い合わせください。
UDM マッピング テーブル
| ログフィールド | UDM マッピング | ロジック |
|---|---|---|
event |
extensions.auth.type |
マッピング: "Failed Login", "SNC Login", "Admin Login", "Impersonation" → MACHINE |
event_created |
metadata.event_timestamp |
yyyy-MM-dd HH:mm:ss として解析 |
event_type |
metadata.event_type |
名前変更済み/マッピング済み |
event |
metadata.product_event_type |
event != `` の場合にマッピングされます |
ip_address |
principal.ip |
統合済み |
user |
principal.user.userid |
user != `` の場合にマッピングされます |
created_by |
target.user.userid |
created_by != `` の場合にマッピングされます |
snc_user |
target.user.userid |
snc_user != `` の場合にマッピングされます |
timestamp |
event1.idm.read_only_udm.metadata.event_timestamp |
変更履歴からマッピング |
data.sys_id |
event1.idm.read_only_udm.metadata.product_log_id |
変更履歴からマッピング |
data.message_data |
event1.idm.read_only_udm.metadata.description |
変更履歴からマッピング |
data.source |
event1.idm.read_only_udm.principal.resource.name |
変更履歴からマッピング |
source |
event1.idm.read_only_udm.additional.fields |
変更履歴からマッピング |
data.sys_created_on |
event1.idm.read_only_udm.metadata.collected_timestamp |
変更履歴からマッピング |
data.sys_created_by |
event1.idm.read_only_udm.principal.user.userid |
変更履歴からマッピング |
data.user |
event1.idm.read_only_udm.principal.user.userid |
変更履歴からマッピング |
source_instance |
event1.idm.read_only_udm.principal.namespace |
変更履歴からマッピング |
data.role |
event1.idm.read_only_udm.target.resource.attribute.roles |
変更履歴からマッピング |
data.granted_by |
event1.idm.read_only_udm.target.user.userid |
変更履歴からマッピング |
data.level |
event1.idm.read_only_udm.security_result.severity |
変更履歴からマッピング |
data.state |
event1.idm.read_only_udm.security_result.action_details |
変更履歴からマッピング |
変更履歴
さらにサポートが必要な場合 コミュニティ メンバーや Google SecOps のプロフェッショナルから回答を得ることができます。