カスタムジョブ統合ガイド

カスタムジョブ統合ガイド
本ガイドでは、カスタム実行ファイルをKEPMのジョブタスクとして統合する流れを、バイナリのビルドとデプロイ、ジョブJSONの作成、MQTT接続と構造化ログのパブリッシュまで順に取り扱います。スケジュール実行やエージェント起動時に動くツールが、本番環境で正しく動作するために必要な事項を扱います。
統合の概要をまだ読んでいない場合は、そちらから始めてください。用語の整理、各要素のつながり、ジョブタスクがユースケースに適するパターンについて説明しています。
バイナリのビルドとデプロイ
ビルドの方針
バイナリの実装言語は任意です。エージェントはフレームワークやランタイムを強制せず、子プロセスとして実行ファイルを起動し、終了コードを追跡し、出力を取り込みます。想定されるパターンは単純で、起動して処理を行い、意味のある終了コードで終了します。
最初から押さえておきたい点:
OSごとに1ビルド: Windows、Linux、macOSをサポートする場合はプラットフォームごとに別バイナリを用意します。OSごとにジョブJSONを分ける方法と、1つのジョブに複数タスクと条件を載せる方法がありますが、プラットフォーム別ビルドの方がシンプルで保守しやすくなります。
単一の目的: スキャン、レポート、メンテナンスなど、処理したら終了する設計にします。ジョブタスク用のバイナリを常駐デーモンとして設計しないでください。その用途はプラグインパターン向けです。
MQTTでログ出力: 標準出力に頼らず、構造化ログメッセージを
KeeperLoggerMQTTトピックへパブリッシュする計画にします。詳細は手順3をご参照ください。
エンドポイントへのバイナリの配置
バイナリはエージェントのアプリケーションルート配下に配置します。推奨レイアウトでは、フルパスを明示しなくても名前でバイナリを解決できます。
ジョブJSONではタスクの command フィールドに {CommandName} のみを指定します (パスなし)。ジョブランナーは Jobs/bin/{CommandName}/ を先に検索し、その後に PATH を検索します。
このレイアウトが使えない場合は、executablePath に絶対パスを指定します。ジョブスキーマ上 command は必須のままですが、解決には executablePath が優先されます。
クロスプラットフォームジョブと osFilter
osFilterジョブのルートに osFilter を設定すると、各エンドポイントではOSに一致するタスクだけが実行されます。osFilter で現在のOSが除外されている場合、バリデータはそのタスクのバイナリがディスクに存在するかどうかのチェックも行いません。つまり、Linuxエージェントを含むフリートにWindows用ジョブを配布しても検証エラーにはなりません。
複数OSを扱う場合、最も単純なのはプラットフォームごとに別のジョブJSONファイル (例: my-tool-windows.json、my-tool-linux.json) を用意し、それぞれにバイナリパスと osFilter を書く方法です。1つのジョブに複数タスクを載せ、各タスクに osFilter 条件を付けることもできますが、保守は複雑になりがちです。
実行コンテキスト
タスクの ExecutionType で、プロセス起動時にエージェントが使うアカウントを制御します。
Service
デフォルト。エージェントのサービスアカウントで実行します。マシン全体へのアクセスが必要で対話ユーザーセッションは不要なバックグラウンドタスク (セキュリティスキャン、メンテナンスジョブ、コンプライアンスレポートなど) に使います。
User
ログオン中のユーザーセッションで実行します。ツールが対話的にユーザープロファイルへアクセスする必要がある場合に限って使います。ユーザーセッションのプロセスは、次節で述べる追加の信頼チェックの対象になります。
UserDesktop
ユーザーのデスクトップセッションで実行します。注意点は User と同様です。
多くのカスタムツールでは Service が適切です。User または UserDesktop を使う場合は、署名とプロセス信頼の節をよく読んでください。管理者以外のユーザーセッションでは追加の制限がかかります。
コード署名とプロセス信頼
ジョブJSONを一行も書く前に理解しておくべき重要な内容です。エージェントがバイナリをどう信頼するかによって、MQTT接続の成否や、プラグイン階層のHTTPS呼び出しがデータを返すか、 403 になるかが決まります。
エージェントによるプロセス登録の仕組み
ジョブランナーがタスクとしてバイナリを起動すると、起動直後にそのプロセスがエージェントの起動済みプロセス登録簿に追加されます。この登録により、次が付与されます。
ローカルMQTTブローカーへのアクセス
/api/PluginSettings/...などプラグイン階層HTTPSエンドポイントの呼び出し許可
登録はバイナリが最初の接続を行う前に行われるため、通常どおりジョブランナーから起動されたジョブタスクが、MQTT接続やプラグイン設定呼び出しのために証明書チェックをパスする必要はありません。
証明書チェックが走るタイミング
証明書チェックは、すでに起動済みプロセス登録簿にないプロセスをエージェントが扱うときに実行されます。以下の2ケースがあります。
ジョブランナーの登録が完了する前にバイナリが起動している (起動時の競合)。エージェントは証明書ベースのチェックにフォールバックします。対策として、最初のMQTT接続で短いリトライループを入れます。
ジョブではなく手動でバイナリが起動されている (シェル、スクリプト、エクスプローラーなど)。この場合、実行ファイルの署名をエンドポイント特権マネージャーの証明書、または
Settings:AlternativeSignaturesに列挙されたサムプリントのいずれかと照合する必要があります。未署名のバイナリはこの経路では失敗します。
証明書サムプリントの追加
ジョブ外で起動したバイナリからもMQTTやプラグイン設定に接続する必要がある場合 (開発やテスト中など)、コード署名証明書のサムプリントを appsettings.json の Settings:AlternativeSignatures に追加します。
Windowsでサムプリントを取得する例:
サムプリントはスペースなしの40文字の16進文字列として指定します。署名証明書が複数ある場合は複数列挙できます。
appsettings.json を保存したらエンドポイント特権マネージャーサービスを再起動します。これらの設定は起動時に読み込まれます。
ユーザーセッション向け AllowedNonAdminExecutables
AllowedNonAdminExecutablesバイナリがユーザーセッションで動作し (ExecutionType: User または UserDesktop)、かつプロセス所有者が管理者でない場合、証明書チェックの後に追加の条件があります。実行ファイルのベース名 (パスなし、.exe なし) が Settings:AllowedNonAdminExecutables に含まれている必要があります。
このチェックは、エージェントのサービスアカウントで動く Service タスクには適用されず、システムセッションの信頼ルールに従います。ツールを常に Service のジョブタスクとしてだけ実行する場合は、この設定は不要です。
推奨運用
本番ビルドはすべて署名する (WindowsはAuthenticode、macOSはApple Developer ID、Linuxはデプロイで強制する場合はGPG署名パッケージやIMA署名など)。
Linuxではエージェントのプロセス信頼は主にジョブランナーによる起動に依存します。証明書チェック経路を避けるため、バイナリは常にジョブタスク経由で起動するようにします。
ジョブ起動以外の文脈でもMQTTやプラグイン設定へのアクセスが必要なときは、サムプリントを
Settings:AlternativeSignaturesに追加する。ジョブ用バイナリは
Jobs/配下に置き、Plugins/配下には置かない。 プラグイン用ディレクトリのパスにはより厳しい検証ルールが適用されますが、それはJobs/bin/のバイナリには当てはまりません。特別な理由がない限り
Serviceで実行する。
ジョブJSONの作成
ジョブファイルとその配置
ジョブは以下の場所に保存するJSONファイルです。
ファイル内の id フィールドは、拡張子 .json を除いたファイル名と完全一致する必要があります。例: secrets-scanner.json には "id": "secrets-scanner" を含めます。
重要: ジョブIDにはハイフンを使い、アンダースコアは使わないでください。MQTTブローカーはクライアントIDからジョブIDを取り出す際にアンダースコアで分割します。secrets_scanner のようなIDはクライアントIDの解釈を壊し、パブリッシュ許可エラーの原因になります。
Last Known Good と安全なデプロイ
多くのデプロイでは、エージェントがLast Known Good (ConfigurationLkg) を有効にした状態で動作します。各ジョブのJSONの暗号化された参照コピーを保持し、Jobs/ ディレクトリが参照と食い違っていないか監視します。手編集などでファイルが参照と一致しないと検出された場合、参照コピーからファイルを復元し、変更は取り消されます。
そのため、ジョブを Jobs/ に直接ファイルを置いてデプロイしないでください。 代わりに、信頼できる書き込み経路のいずれかを使います。
方法1: ローカルHTTPS API。 ジョブJSONをエージェントの POST /api/Jobs にPOSTします。ファイルとLast Known Goodの参照を原子的に更新します。APIの詳細は手順4をご参照ください。
方法2: JobUpdate ポリシー。 管理フリートでは、Keeperコンソール経由で配信される JobUpdate ポリシーが標準です。構成ポリシープロセッサがジョブファイルと参照コピーを許可された操作として書き込みます。現在のポリシースキーマとコンソール上の手順は、Keeper管理者に確認してください。
ジョブJSONの構造
Windows向けの完全な注釈付き例です。
主なフィールド:
id: ファイル名と一致させる。ハイフンのみ。アンダースコアは不可。
enabled: true にする。enabled: false のジョブは手動トリガーがあっても実行されません。
schedule: タイマートリガー。intervalMinutes は実行の間隔 (分) であり、時刻に揃えた周期ではありません。120 は2時間ごとです。
events: イベントトリガー。Startup はエージェント起動時に1回、ジョブ読み込み後に実行されます。schedule と events の両方を持てます。どちらも独立して実行を引き起こし得ます。
osFilter: ジョブを実行するOS。対象プラットフォームだけ true にします。
mqttTopics: タスクがパブリッシュ・サブスクライブしてよいMQTTトピック。ブローカーがこのリストを強制します。ここに KeeperLogger がないと、MQTT接続に成功してもパブリッシュは拒否されます。
tasks: 実行するステップの配列。多くのカスタムツールでは1タスクで足ります。タスクは順番に実行されます。
arguments: 変数置換に対応。{KeeperApiBaseUrl} はエージェントがローカルHTTPS APIのベースURL (例: https://127.0.0.1:6889) に置き換えます。バイナリはこのフラグを解釈し、実行時にプラグイン設定を呼び出します。コード例は概要ページをご参照ください。
スケジュールオプション
ジョブには4種類のスケジュールモードがあります。1ジョブで有効にできるモードは1つだけです。
間隔: スケジューラ起動からN分ごと:
Cron: 標準的な5フィールド (分、時、日、月、曜日):
1回限り: 指定したUTC時刻に1回だけ:
カレンダー: 週または月の特定曜日・特定時刻:
起動時と間隔のタイミング
Startup イベントと intervalMinutes の両方があるジョブは、エージェント起動時に1回実行されたあと、そこから間隔どおりに再実行されます。間隔タイマーは独立して動作するため、起動時実行と最初の間隔実行の関係は、対象エージェントのバージョンで実測せずに固定関係とみなさないでください。
エージェント起動時は、ジョブの読み込みと KeeperLogger がメッセージを受け付け可能になった後に、Startupジョブがトリガーされます。間隔タイマーの最初の刻みは、Startup実行の完了時刻ではなく、スケジューラ初期化から設定された分数後です。
ジョブのデプロイ
ローカルHTTPS APIの利用
エージェントはループバック上でジョブ管理用のREST APIを公開します。HTTPSリスナーは Settings:KestrelHttpsPort (多くの場合 6889) です。ジョブ管理の各エンドポイントには管理用階層の認可が必要です。認証方式 (多くの場合、環境用にプロビジョニングされたクライアント証明書による相互TLS) はデプロイチームから案内されます。
ジョブの作成または更新:
主なジョブ管理エンドポイント:
POST
/api/Jobs
ジョブの作成
PUT
/api/Jobs/{jobId}
既存ジョブの置換
DELETE
/api/Jobs/{jobId}
ジョブの削除
POST
/api/Jobs/validate
保存せずにJSONの検証
GET
/api/Jobs
ジョブ一覧
GET
/api/Jobs/{jobId}
1件のジョブ定義の取得
POST
/api/Jobs/{jobId}/trigger
手動での実行依頼
プラグイン設定エンドポイントや認可の詳細を含む完全なAPIリファレンスは、HTTPリファレンスをご参照ください。
検証にはバイナリの存在が必要
POST /api/Jobs と POST /api/Jobs/validate はジョブバリデータを実行し、呼び出し時点でタスクの実行ファイルがディスク上に存在するかを確認します。つまり、APIでジョブを登録する前にエンドポイントへバイナリを配置するか、バイナリが想定パスに既にあるマシンで検証する必要があります。
ジョブの osFilter が現在のOSを除外している場合、その検証実行ではバイナリ存在チェックはスキップされます。WindowsホストからLinux専用ジョブだけを登録するといった運用が可能です。
JobUpdate ポリシーの利用
JobUpdate ポリシーの利用管理フリートでは、Keeperコンソール経由の JobUpdate ポリシーが典型的なデプロイ経路です。Keeper管理者がポリシー封筒を構成してエンドポイントへ配信し、こちらはジョブJSONを用意します。現在のポリシースキーマとコンソール手順は管理者に確認してください。関連: ジョブの作成、変更、または削除
MQTT接続とログのパブリッシュ
バイナリをデプロイしジョブを登録したら、ログがエージェントのログパイプラインへ流れるよう、MQTT接続を設定します。
手順1: ジョブでMQTT権限を宣言する
ジョブのルートオブジェクトに mqttTopics を追加します。ブローカーがこのリストを強制するため、トピックが欠けているとMQTT接続自体は成功してもパブリッシュは拒否されます。
カスタムイベントトピックへもパブリッシュする場合は、そのトピックも allowedPublications に追加します。
allowedSubscriptions はMQTTトピックを購読する場合にのみ必要です。多くのジョブタスク用バイナリでは不要です。
手順2: プラグイン設定からブローカーアドレスを読む
ジョブが少なくとも1エントリを含む mqttTopics を定義している場合、エージェントはタスク起動前に以下の環境変数を設定します。
KEEPER_JOB_ID
ジョブJSONの id フィールド
KEEPER_JOB_NAME
ジョブJSONの name フィールド
バイナリはMQTTクライアントIDのために KEEPER_JOB_ID が必要で、ブローカーアドレスはプラグイン設定から取得します。起動時の例:
ここで覚えておきたい点:
この呼び出しにはプラグイン階層の認証が必要です。 エージェントが起動したプロセスからのみ成功します。手動起動のコピーは
403になります。エージェントはループバックに自己署名TLS証明書を使うことがあります。 組織がエージェント証明書用のCAバンドルを配布している場合はHTTPクライアントに設定します。ない場合は、セキュリティポリシーに従い、ループバック限定で証明書検証を無効にします。
失敗時はデフォルトにフォールバックしつつ警告ログを残す。 本番でプラグイン設定の取得に失敗したことは、運用者が把握すべき構成上の問題です。
手順3: MQTTクライアントIDを組み立てる
ブローカーはクライアントIDをジョブと突き合わせて検証します。ジョブタスク向けの形式は以下のとおりです。
意味は以下のとおりです。
{KEEPER_JOB_ID}: エージェントが設定した環境変数の値{ExecutableToken}: バイナリの短い固定名 (パス文字・スペース・アンダースコアなし){ProcessId}: 現在のOSプロセスID (10進整数)
ジョブIDにアンダースコアを含めないでください。 ブローカーは _ でクライアントIDを分割してジョブID部分を取り出します。ジョブIDに secrets_scanner のようなアンダースコアがあると誤って解釈され、接続とジョブの対応付けやパブリッシュの許可判定に失敗します。ハイフンを使います (例: secrets-scanner)。
手順4: MQTTブローカーに接続する
プラグイン設定で取得したホストとポートに対し、TLSで接続します。ブローカーは暗号化接続を要求し、平文TCPは受け付けません。
タイミング: 起動直後にMQTTへ接続し接続拒否になる場合、接続試行とエージェント側のプロセス登録完了との競合の可能性があります。失敗とみなす前に1〜2秒程度の短いリトライループを入れます。
クライアントライブラリが対応していればMQTT v5を優先します。エージェント内部コンポーネントはMQTT v5を使用します。
手順5: KeeperLoggerへログメッセージをパブリッシュする
トピック KeeperLogger に対し、QoS 1、retain: false でパブリッシュします。各ペイロードは以下の形の単一JSONオブジェクトにします。プロパティ名の大文字小文字は区別されます。
フィールドの説明:
Id
メッセージごとに新しいランダムUUID文字列
Version
1
RespondToTopic
null
MetaData.MessageType
4 (または文字列 "Log")
MetaData.LogLevel
0 Debug、1 Info、2 Warning、3 Error、4 Critical、5 Verbose、または対応する文字列
MetaData.Source
ログに表示されるツール名
MetaData.Category
フェーズやコンポーネントの短いラベル
MetaData.Message
人が読めるテキスト。空不可。生のシークレット値は含めず、件数やパスなどに留める
MetaData.CorrelationId
任意のトレースID。未使用は ""
MetaData.Context
任意の追加テキスト。未使用は ""
Pythonでのパブリッシュ例:
注意点:
Messageは空にできません。 ロガーは空メッセージを拒否します。ログに生のシークレットを含めない。 件数、ファイルパス、状態のみを記録します。
MessageやContext内の生の改行は避ける。 スクレイプしたファイル内容をログに出す場合はスペースに置き換えます。
任意: MQTTでのジョブ進捗
構造化ログを KeeperLogger に送るのとは別に、下流の購読者がジョブ実行イベントを観測する必要がある場合、ジョブのイベントトピックへパブリッシュできます。
デフォルトのイベントトピックのパターンは Jobs/{jobId}/events です。ジョブのルートに eventTopic フィールドでカスタムトピックを指定することもできます。
イベントトピックは allowedPublications にも含める必要があります。 リストにないと接続に成功してもパブリッシュは拒否されます。eventTopic を追加するときは、eventTopic と allowedPublications の両方に同じトピック文字列があることを確認してください。
起動前チェックリスト
パイロットエンドポイントで全項目を確認してからフリートへ展開してください。
1
POST /api/Jobs 呼び出し前に、エンドポイント上で解決された command / executablePath にバイナリが存在する
2
ジョブの id がファイル名と一致し、id にアンダースコアがない
3
enabled が true
4
osFilter が対象プラットフォームと一致する
5
mqttTopics.allowedPublications に KeeperLogger が含まれる。eventTopic を使う場合はそのトピックも含まれる
6
デプロイ後 GET /api/Jobs にジョブが表示される
7
POST /api/Jobs/{jobId}/trigger でタスクが成功する (管理用認可が必要)
8
実行中タスクに環境変数 KEEPER_JOB_ID と KEEPER_JOB_NAME が渡る
9
実行中タスク内から GET /api/PluginSettings/KeeperPrivilegeManager が broker.host と broker.port を返す
10
MQTTがTLSで接続でき、クライアントIDが {jobId}_Token_{pid} 形式である
11
KeeperLogger へのパブリッシュが成功し、オペレーターのログ画面にメッセージが出る
12
eventTopic を使う場合、そのトピックへのパブリッシュが成功する
13
コード署名: 本番バイナリは署名済み。必要ならサムプリントが AlternativeSignatures にある
トラブルシューティング
POST /api/Jobs が 403 を返す
管理用認可。証明書が誤っている、または呼び出しプロセスが管理用として認可されていない
POST /api/Jobs が検証エラーで 400 を返す
検証ホスト上のパスにバイナリがない。先にバイナリをデプロイする
GET /api/Jobs に出るが実行されない
enabled: true か確認。osFilter がエンドポイントのOSと一致するか確認
手編集した Jobs/*.json が元に戻る
Last Known Good が有効。APIまたは JobUpdate ポリシーを使う
タスク内から GET /api/PluginSettings/... が 403
プロセスが信頼済みとして登録されていない。手動ではなくジョブランナーから起動されているか確認
MQTT接続が拒否される
起動済みプロセス登録簿に載っていない。起動時にリトライロジックを追加
MQTTは接続するがパブリッシュが拒否される
ジョブJSONの mqttTopics.allowedPublications にトピックがない
クライアントIDの解析エラー / ジョブの取り違え
ジョブ id にアンダースコアがある。ハイフンに変更
オペレーター画面にログが出ない
KeeperLogger が未起動または未購読の可能性。管理者に確認
最終更新

