Custom Job Guide
Custom Job Integration Guide
1
{AgentRoot}/Jobs/bin/{CommandName}/{CommandName}.exe (Windows)
{AgentRoot}/Jobs/bin/{CommandName}/{CommandName} (Linux / macOS)"osFilter": {
"windows": true,
"linux": false,
"macOS": false
}ExecutionType
When to use
2
{
"Settings": {
"AlternativeSignatures": [
"A1B2C3D4E5F6789012345678901234567890ABCD"
]
}
}Get-AuthenticodeSignature -FilePath "C:\Path\To\YourTool.exe" |
Select-Object -ExpandProperty SignerCertificate |
Select-Object -ExpandProperty Thumbprint{
"Settings": {
"AllowedNonAdminExecutables": [
"MyTool"
]
}
}3
{AgentRoot}/Jobs/{job-id}.json{
"id": "secrets-scanner",
"name": "Secrets Scanner",
"description": "Scans for exposed credentials and publishes results to KeeperLogger.",
"enabled": true,
"schedule": {
"intervalMinutes": 120
},
"events": [
{ "eventType": "Startup" }
],
"osFilter": {
"windows": true,
"linux": false,
"macOS": false
},
"mqttTopics": {
"allowedPublications": ["KeeperLogger"],
"allowedSubscriptions": []
},
"parameters": [],
"tasks": [
{
"id": "run-scanner",
"name": "Run scanner",
"ExecutionType": "Service",
"command": "SecretScanner",
"executablePath": "C:\\Program Files\\KeeperPrivilegeManager\\Jobs\\bin\\SecretScanner\\SecretScanner.exe",
"arguments": "--scan --keeper-api-base={KeeperApiBaseUrl}",
"timeoutSeconds": 3600,
"continueOnFailure": false,
"scriptType": "Auto"
}
]
}"schedule": { "intervalMinutes": 120 }"schedule": { "cronExpression": "0 3 * * *" }"schedule": { "runAt": "2025-06-01T02:00:00Z" }"schedule": {
"calendar": [
{ "time": "03:00", "daysOfWeek": ["Monday", "Wednesday", "Friday"] }
]
}4
Invoke-RestMethod -Method Post `
-Uri "https://127.0.0.1:6889/api/Jobs" `
-ContentType "application/json" `
-Certificate $adminClientCert `
-Body (Get-Content -Raw .\secrets-scanner.json)curl -s -X POST https://127.0.0.1:6889/api/Jobs \
--cert /path/to/client.pem \
--key /path/to/client.key \
--cacert /path/to/ca.pem \
-H "Content-Type: application/json" \
-d @secrets-scanner.jsonMethod
Path
Purpose
5
"mqttTopics": {
"allowedPublications": ["KeeperLogger"],
"allowedSubscriptions": []
}Variable
Value
import os
import argparse
import json
import ssl
import urllib.request
FALLBACK_HOST = "127.0.0.1"
FALLBACK_PORT = 8675
def load_broker_settings(keeper_api_base: str) -> tuple[str, int]:
url = f"{keeper_api_base}/api/PluginSettings/KeeperPrivilegeManager"
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE # self-signed on loopback; use CA bundle if provided
try:
with urllib.request.urlopen(url, context=ctx, timeout=10) as resp:
settings = json.loads(resp.read().decode())
return settings.get("broker.host", FALLBACK_HOST), int(settings.get("broker.port", FALLBACK_PORT))
except Exception as exc:
print(f"[WARNING] Plugin Settings unavailable ({exc}). Using defaults.")
return FALLBACK_HOST, FALLBACK_PORT
parser = argparse.ArgumentParser()
parser.add_argument("--keeper-api-base", required=True)
args = parser.parse_args()
job_id = os.environ.get("KEEPER_JOB_ID", "")
job_name = os.environ.get("KEEPER_JOB_NAME", "")
broker_host, broker_port = load_broker_settings(args.keeper_api_base){KEEPER_JOB_ID}_{ExecutableToken}_{ProcessId}import os
job_id = os.environ.get("KEEPER_JOB_ID", "unknown")
pid = os.getpid()
client_id = f"{job_id}_SecretScanner_{pid}"
# Example result: "secrets-scanner_SecretScanner_48292"import ssl
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, reason_code, properties):
if reason_code == 0:
print("Connected to MQTT broker")
else:
print(f"MQTT connection failed: {reason_code}")
mqttc = mqtt.Client(
mqtt.CallbackAPIVersion.VERSION2,
client_id=client_id,
protocol=mqtt.MQTTv5
)
# TLS configuration — use CA bundle if provided, otherwise trust loopback cert
tls_ctx = ssl.create_default_context()
tls_ctx.check_hostname = False
tls_ctx.verify_mode = ssl.CERT_NONE # replace with CA bundle if available
mqttc.tls_set_context(tls_ctx)
mqttc.on_connect = on_connect
mqttc.connect(broker_host, broker_port, keepalive=60)
mqttc.loop_start(){
"Id": "b2e7f4a8-6c2d-4b1e-9f3a-8c1d2e3f4a5b",
"Version": 1,
"RespondToTopic": null,
"MetaData": {
"MessageType": 4,
"LogLevel": 1,
"Source": "SecretScanner",
"Category": "SecretsScan",
"Message": "Scan complete: 0 issues detected.",
"CorrelationId": "",
"Context": ""
}
}Field
Value
import uuid
import json
def publish_log(client, source: str, category: str, message: str, level: int = 1):
payload = {
"Id": str(uuid.uuid4()),
"Version": 1,
"RespondToTopic": None,
"MetaData": {
"MessageType": 4,
"LogLevel": level,
"Source": source,
"Category": category,
"Message": message,
"CorrelationId": "",
"Context": ""
}
}
client.publish("KeeperLogger", json.dumps(payload), qos=1, retain=False)
# Usage
publish_log(mqttc, "SecretScanner", "SecretsScan", "Scan complete: 0 issues detected.")
publish_log(mqttc, "SecretScanner", "SecretsScan", "3 files could not be read.", level=2)Optional: Job Progress Over MQTT
{
"id": "secrets-scanner",
"eventTopic": "Jobs/secrets-scanner/events",
"mqttTopics": {
"allowedPublications": [
"KeeperLogger",
"Jobs/secrets-scanner/events"
],
"allowedSubscriptions": []
}
}Pre-Launch Checklist
#
Check
Troubleshooting
Symptom
Where to look
Last updated
Was this helpful?

