diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 70fb4d23359..3726beb5885 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -431,6 +431,7 @@ /packages/panw_metrics @elastic/obs-infraobs-integrations /packages/pfsense @elastic/integration-experience /packages/php_fpm @elastic/obs-infraobs-integrations +/packages/ping_directory @elastic/security-service-integrations /packages/ping_federate @elastic/security-service-integrations @elastic/sit-crest-contractors /packages/ping_one @elastic/security-service-integrations @elastic/sit-crest-contractors /packages/platform_observability @elastic/stack-monitoring diff --git a/packages/ping_directory/LICENSE.txt b/packages/ping_directory/LICENSE.txt new file mode 100644 index 00000000000..809108b857f --- /dev/null +++ b/packages/ping_directory/LICENSE.txt @@ -0,0 +1,93 @@ +Elastic License 2.0 + +URL: https://www.elastic.co/licensing/elastic-license + +## Acceptance + +By using the software, you agree to all of the terms and conditions below. + +## Copyright License + +The licensor grants you a non-exclusive, royalty-free, worldwide, +non-sublicensable, non-transferable license to use, copy, distribute, make +available, and prepare derivative works of the software, in each case subject to +the limitations and conditions below. + +## Limitations + +You may not provide the software to third parties as a hosted or managed +service, where the service provides users with access to any substantial set of +the features or functionality of the software. + +You may not move, change, disable, or circumvent the license key functionality +in the software, and you may not remove or obscure any functionality in the +software that is protected by the license key. + +You may not alter, remove, or obscure any licensing, copyright, or other notices +of the licensor in the software. Any use of the licensor’s trademarks is subject +to applicable law. + +## Patents + +The licensor grants you a license, under any patent claims the licensor can +license, or becomes able to license, to make, have made, use, sell, offer for +sale, import and have imported the software, in each case subject to the +limitations and conditions in this license. This license does not cover any +patent claims that you cause to be infringed by modifications or additions to +the software. If you or your company make any written claim that the software +infringes or contributes to infringement of any patent, your patent license for +the software granted under these terms ends immediately. If your company makes +such a claim, your patent license ends immediately for work on behalf of your +company. + +## Notices + +You must ensure that anyone who gets a copy of any part of the software from you +also gets a copy of these terms. + +If you modify the software, you must include in any modified copies of the +software prominent notices stating that you have modified the software. + +## No Other Rights + +These terms do not imply any licenses other than those expressly granted in +these terms. + +## Termination + +If you use the software in violation of these terms, such use is not licensed, +and your licenses will automatically terminate. If the licensor provides you +with a notice of your violation, and you cease all violation of this license no +later than 30 days after you receive that notice, your licenses will be +reinstated retroactively. However, if you violate these terms after such +reinstatement, any additional violation of these terms will cause your licenses +to terminate automatically and permanently. + +## No Liability + +*As far as the law allows, the software comes as is, without any warranty or +condition, and the licensor will not be liable to you for any damages arising +out of these terms or the use or nature of the software, under any kind of +legal claim.* + +## Definitions + +The **licensor** is the entity offering these terms, and the **software** is the +software the licensor makes available under these terms, including any portion +of it. + +**you** refers to the individual or entity agreeing to these terms. + +**your company** is any legal entity, sole proprietorship, or other kind of +organization that you work for, plus all organizations that have control over, +are under the control of, or are under common control with that +organization. **control** means ownership of substantially all the assets of an +entity, or the power to direct its management and policies by vote, contract, or +otherwise. Control can be direct or indirect. + +**your licenses** are all the licenses granted to you for the software under +these terms. + +**use** means anything you do with the software requiring one of your licenses. + +**trademark** means trademarks, service marks, and similar rights. diff --git a/packages/ping_directory/_dev/build/build.yml b/packages/ping_directory/_dev/build/build.yml new file mode 100644 index 00000000000..ac5efe47b5c --- /dev/null +++ b/packages/ping_directory/_dev/build/build.yml @@ -0,0 +1,3 @@ +dependencies: + ecs: + reference: git@v9.4.0 diff --git a/packages/ping_directory/_dev/build/docs/README.md b/packages/ping_directory/_dev/build/docs/README.md new file mode 100644 index 00000000000..a6c598e05d8 --- /dev/null +++ b/packages/ping_directory/_dev/build/docs/README.md @@ -0,0 +1,104 @@ +# PingDirectory Integration for Elastic + +## Overview + +[PingDirectory](https://www.pingidentity.com/en/product/pingdirectory.html) is an **enterprise-grade LDAP directory server** and identity data store. It provides high-performance, scalable directory services for managing user identities, credentials, and access control across hybrid environments — combining authentication, authorization, and directory data management into a unified platform for **critical identity infrastructure**. + +This integration collects data from PingDirectory log files using the Elastic Agent filestream input, or over the network using the Elastic Agent UDP input. It provides visibility into LDAP connection activity, requests, results, and security negotiation events across your PingDirectory environment. + +### Compatibility + +The PingDirectory integration is compatible with **PingDirectory version 11.0.0.2 and above**. + +### How it works + +The integration uses the Elastic Agent filestream input to collect log files generated by PingDirectory on a configurable path, or the UDP input to receive logs forwarded by a PingDirectory Syslog Text Access Log Publisher. Each collection cycle: + +1. Reads log entries from the configured PingDirectory LDAP Access log file (`access.log`), or receives them over UDP when syslog forwarding is used. +2. Parses each log line using a grok pattern to extract fields such as timestamp, connection ID, operation type, instance name, client and server IP/port, requester DN, and result code. +3. Extracts operation-specific details including request type, search filters, response time, and result codes from the access log record. +4. Emits each log entry as an individual event for ingestion and enrichment via the built-in ingest pipeline. + +## What data does this integration collect? + +The PingDirectory integration collects the following types of data: + +| Data stream | Description | +|---|---| +| `ldap_access` | LDAP access logs generated by PingDirectory, including connection and disconnection events, LDAP requests and results, security negotiation details, client and server addresses, requester identities, and response times for monitoring LDAP client activity across your directory environment. + +### Supported use cases + +* **LDAP connection monitoring**: Track connect, disconnect, and security negotiation events to gain visibility into client connection activity and TLS/cipher usage across your directory environment. + +* **Operational troubleshooting and access analysis**: Analyze who performed which LDAP operations, from which client IP, with what result code, and at what response time to investigate failed binds, slow searches, and unauthorized access attempts. + +## What do I need to use this integration? + +### From PingDirectory + +* **PingDirectory deployment**: An active PingDirectory server configured to generate LDAP Access logs. +* **Access logging enabled**: The File-Based Access Logger must be enabled to record LDAP operations, or a Syslog Text Access Log Publisher must be configured to forward access logs over UDP. To configure the publisher: in the PingDirectory Administrative Console, go to **Configuration → Log Publishers → New Log Publisher → Syslog Text Access Log Publisher**, create a **Syslog External Server** with the Elastic Agent host and UDP port (must match the integration's **Listen Port**, default `9602`), then enable and save the publisher. +* **Log access**: Elastic Agent must have access to the Access log files on the PingDirectory host, or network access to receive the forwarded syslog UDP traffic. +* **Elastic Agent**: Version 8.18+ or 9.0+ with Fleet enrollment. + +## How do I deploy this integration? + +### Agent-based deployment + +Elastic Agent must be installed. For more details, check the Elastic Agent [installation instructions](docs-content://reference/fleet/install-elastic-agents.md). You can install only one Elastic Agent per host. + +Elastic Agent is required to stream data from the syslog or log file receiver and ship the data to Elastic, where the events will then be processed via the integration's ingest pipelines. + +### Configure + +1. In Kibana, navigate to **Fleet → Integrations** and search for **PingDirectory**. +2. Click **Add PingDirectory**. +3. Configure the integration settings: + + * To collect from a local log file, enable the filestream input and specify the **Paths** to the PingDirectory LDAP Access log file(s), for example: + /opt/pingdirectory/logs/access* + * To receive logs forwarded over the network, enable the UDP input and set the **Listen Address** and **Listen Port** to match the Syslog External Server configured on PingDirectory. + * Configure any optional collection settings as required. +4. Select **Save and continue** to save the integration. +5. Add the integration to an existing Agent policy or create a new one. +6. Verify that LDAP Access events are being ingested into Elasticsearch. + +### Validation + +#### Dashboard populated + +1. In the top search bar in Kibana, search for **Dashboards**. +2. In the search bar, type **PingDirectory**. +3. Open the **[Logs PingDirectory] LDAP Access** dashboard. +4. Verify that the visualizations are populated with LDAP access data, including connection events, requester identities, result codes, and client IP addresses. + +## Scaling + +For more information on architectures that can be used for scaling this integration, check the [Ingest Architectures](https://www.elastic.co/docs/manage-data/ingest/ingest-reference-architectures) documentation. + +## Troubleshooting + +* **No data collected**: Verify that the PingDirectory File-Based Access Logger is enabled and generating log entries, or that the Syslog Text Access Log Publisher is enabled and pointed at the correct Elastic Agent host and port. Confirm that the configured log file path or UDP listener matches the location of the Access logs. + +For help with Elastic ingest tools, check [Common problems](https://www.elastic.co/docs/troubleshoot/ingest/fleet/common-problems). + +## Reference + +### LDAP Access + +The `ldap_access` data stream provides LDAP access logs from ping_directory. + +#### LDAP Access fields + +{{fields "ldap_access"}} + +### Example event + +#### LDAP Access + +{{event "ldap_access"}} + +### Inputs used + +{{ inputDocs }} \ No newline at end of file diff --git a/packages/ping_directory/_dev/deploy/docker/docker-compose.yml b/packages/ping_directory/_dev/deploy/docker/docker-compose.yml new file mode 100644 index 00000000000..d31b828b80b --- /dev/null +++ b/packages/ping_directory/_dev/deploy/docker/docker-compose.yml @@ -0,0 +1,13 @@ +version: '2.3' +services: + ping_directory-udp-ldap_access: + image: docker.elastic.co/observability/stream:v0.22.0 + volumes: + - ./sample_logs:/sample_logs:ro + command: log --start-signal=SIGHUP --delay=5s --addr elastic-agent:9599 -p=udp /sample_logs/test-ldap_access.log + ping_directory-logfile-ldap_access: + image: alpine + volumes: + - ./sample_logs:/sample_logs:ro + - ${SERVICE_LOGS_DIR}:/var/log + command: /bin/sh -c "cp /sample_logs/* /var/log/" diff --git a/packages/ping_directory/_dev/deploy/docker/sample_logs/test-ldap_access.log b/packages/ping_directory/_dev/deploy/docker/sample_logs/test-ldap_access.log new file mode 100644 index 00000000000..3891c09e368 --- /dev/null +++ b/packages/ping_directory/_dev/deploy/docker/sample_logs/test-ldap_access.log @@ -0,0 +1,3 @@ +[25/May/2026:18:30:48.688 +0530] ADD RESULT instanceName="pingdirectory-elastic-test" threadID=9 conn=4 op=1 msgID=2 requesterIP="127.0.0.1" requesterDN="cn=Directory Manager,cn=Root DNs,cn=config" dn="ou=People,dc=example,dc=com" resultCode=0 resultCodeName="Success" qtime=0 etime=24.567 usedPrivileges="bypass-acl" +[25/May/2026:18:32:55.559 +0530] ADD RESULT instanceName="pingdirectory-elastic-test" threadID=10 conn=5 op=1 msgID=2 requesterIP="127.0.0.1" requesterDN="cn=Directory Manager,cn=Root DNs,cn=config" dn="uid=john.doe,ou=People,dc=example,dc=com" resultCode=65 resultCodeName="Object Class Violation" message="Entry 'uid=john.doe,ou=People,dc=example,dc=com' violates the Directory Server schema configuration because it includes attribute 'department' which is not allowed by any of the object classes defined in that entry" qtime=1 etime=3.178 usedPrivileges="bypass-acl" +[25/May/2026:19:29:51.686 +0530] DISCONNECT requesterIP="172.20.240.130" requesterDN="" instanceName="pingdirectory-elastic-test" threadID=125 conn=21 reason="I/O Error" msg="An error occurred while attempting to read data from the client: SSLException: Unrecognized SSL message, plaintext connection? (SSLEngineInputRecord.java:145 SSLEngineInputRecord.java:64 SSLEngineImpl.java:612 SSLEngineImpl.java:506 SSLEngineImpl.java:482 SSLEngine.java:679 TLSConnectionSecurityProvider.java:1463 LDAPRequestHandler.java:240 DirectoryThread.java:358 (11.0.0.2-20260310181715.000Z-8b5f7f2b))" diff --git a/packages/ping_directory/changelog.yml b/packages/ping_directory/changelog.yml new file mode 100644 index 00000000000..d155e5a177e --- /dev/null +++ b/packages/ping_directory/changelog.yml @@ -0,0 +1,6 @@ +# newer versions go on top +- version: '0.1.0' + changes: + - description: Add support of ldap_access datastream. + type: enhancement + link: https://github.com/elastic/integrations/pull/20091 diff --git a/packages/ping_directory/data_stream/ldap_access/_dev/test/pipeline/test-ldap-access.log b/packages/ping_directory/data_stream/ldap_access/_dev/test/pipeline/test-ldap-access.log new file mode 100644 index 00000000000..39a01d22fae --- /dev/null +++ b/packages/ping_directory/data_stream/ldap_access/_dev/test/pipeline/test-ldap-access.log @@ -0,0 +1,10 @@ +[25/May/2026:18:22:45.267 +0530] CONNECT instanceName="pingdirectory-elastic-test" threadID=198 conn=0 from="127.0.0.1" fromPort=44560 to="127.0.0.1" toPort=1636 protocol="LDAP+TLS" clientConnectionPolicy="default" +[25/May/2026:18:22:45.382 +0530] SECURITY-NEGOTIATION requesterIP="127.0.0.1" instanceName="pingdirectory-elastic-test" threadID=124 conn=0 protocol="TLSv1.3" cipher="TLS_AES_256_GCM_SHA384" clientServerHandshakeTimeMillis="87.219" serverOnlyHandshakeTimeMillis="57.181" +[25/May/2026:18:22:45.408 +0530] BIND RESULT instanceName="pingdirectory-elastic-test" threadID=10 conn=0 op=0 msgID=1 requesterIP="127.0.0.1" version="3" dn="" authType="SIMPLE" resultCode=0 resultCodeName="Success" qtime=0 etime=7.884 clientConnectionPolicy="default" +[25/May/2026:18:22:45.416 +0530] DISCONNECT requesterIP="127.0.0.1" requesterDN="" instanceName="pingdirectory-elastic-test" threadID=124 conn=0 reason="Client Unbind" +[25/May/2026:18:27:23.530 +0530] EXTENDED RESULT instanceName="pingdirectory-elastic-test" threadID=29 conn=1 op=0 msgID=1 requesterIP="10.50.15.29" requesterDN="" usingAdminSessionWorkerThread=true requestOID="1.3.6.1.4.1.30221.2.6.13" requestType="Start Administrative Session Extended Request" resultCode=0 resultCodeName="Success" additionalInfo="clientName='config-tool' useDedicatedThreadPool=true" qtime=0 etime=3.381 +[25/May/2026:18:27:23.567 +0530] SEARCH RESULT instanceName="pingdirectory-elastic-test" threadID=29 conn=1 op=2 msgID=3 requesterIP="10.50.15.29" requesterDN="cn=Directory Manager,cn=Root DNs,cn=config" usingAdminSessionWorkerThread=true base="cn=System Information,cn=monitor" scope=0 filter="(objectClass=*)" attrs="instanceRoot" resultCode=0 resultCodeName="Success" qtime=0 etime=2.145 usedPrivileges="bypass-acl" preAuthZUsedPrivileges="use-admin-session" entriesReturned=1 +<30>1 2026-06-23T11:04:12.067Z ub20-50-15-29.cdsys.local PingDirectory 4292 text-access - [23/Jun/2026:16:34:12.067 +0530] SEARCH RESULT product="Directory Server" instanceName="pingdirectory-elastic-test" startupID="ajDlEQ==" conn=52 op=1 msgID=2 requesterIP="10.50.14.255" requesterDN="cn=Directory Manager,cn=Root DNs,cn=config" base="dc=example,dc=com" scope=2 filter="(objectClass=*)" attrs="ALL" resultCode=0 resultCodeName="Success" qtime=0 etime=0.913 usedPrivileges="bypass-acl" entriesReturned=12 +[25/May/2026:18:30:48.688 +0530] ADD RESULT instanceName="pingdirectory-elastic-test" threadID=9 conn=4 op=1 msgID=2 requesterIP="127.0.0.1" requesterDN="cn=Directory Manager,cn=Root DNs,cn=config" dn="ou=People,dc=example,dc=com" resultCode=0 resultCodeName="Success" qtime=0 etime=24.567 usedPrivileges="bypass-acl" +[25/May/2026:18:32:55.559 +0530] ADD RESULT instanceName="pingdirectory-elastic-test" threadID=10 conn=5 op=1 msgID=2 requesterIP="127.0.0.1" requesterDN="cn=Directory Manager,cn=Root DNs,cn=config" dn="uid=john.doe,ou=People,dc=example,dc=com" resultCode=65 resultCodeName="Object Class Violation" message="Entry 'uid=john.doe,ou=People,dc=example,dc=com' violates the Directory Server schema configuration because it includes attribute 'department' which is not allowed by any of the object classes defined in that entry" qtime=1 etime=3.178 usedPrivileges="bypass-acl" +[25/May/2026:19:29:51.686 +0530] DISCONNECT requesterIP="172.20.240.130" requesterDN="" instanceName="pingdirectory-elastic-test" threadID=125 conn=21 reason="I/O Error" msg="An error occurred while attempting to read data from the client: SSLException: Unrecognized SSL message, plaintext connection? (SSLEngineInputRecord.java:145 SSLEngineInputRecord.java:64 SSLEngineImpl.java:612 SSLEngineImpl.java:506 SSLEngineImpl.java:482 SSLEngine.java:679 TLSConnectionSecurityProvider.java:1463 LDAPRequestHandler.java:240 DirectoryThread.java:358 (11.0.0.2-20260310181715.000Z-8b5f7f2b))" diff --git a/packages/ping_directory/data_stream/ldap_access/_dev/test/pipeline/test-ldap-access.log-expected.json b/packages/ping_directory/data_stream/ldap_access/_dev/test/pipeline/test-ldap-access.log-expected.json new file mode 100644 index 00000000000..d80e01d800a --- /dev/null +++ b/packages/ping_directory/data_stream/ldap_access/_dev/test/pipeline/test-ldap-access.log-expected.json @@ -0,0 +1,460 @@ +{ + "expected": [ + { + "@timestamp": "2026-05-25T18:22:45.267+05:30", + "destination": { + "ip": "127.0.0.1", + "port": 1636 + }, + "ecs": { + "version": "9.4.0" + }, + "event": { + "action": "connect", + "category": [ + "iam" + ], + "kind": "event", + "original": "[25/May/2026:18:22:45.267 +0530] CONNECT instanceName=\"pingdirectory-elastic-test\" threadID=198 conn=0 from=\"127.0.0.1\" fromPort=44560 to=\"127.0.0.1\" toPort=1636 protocol=\"LDAP+TLS\" clientConnectionPolicy=\"default\"", + "timezone": "+0530", + "type": [ + "change" + ] + }, + "network": { + "protocol": "ldap+tls" + }, + "observer": { + "name": "pingdirectory-elastic-test" + }, + "ping_directory": { + "ldap_access": { + "client_connection_policy": "default", + "conn": 0, + "thread_id": "198" + } + }, + "related": { + "ip": [ + "127.0.0.1" + ] + }, + "source": { + "ip": "127.0.0.1", + "port": 44560 + } + }, + { + "@timestamp": "2026-05-25T18:22:45.382+05:30", + "ecs": { + "version": "9.4.0" + }, + "event": { + "action": "security-negotiation", + "category": [ + "iam" + ], + "kind": "event", + "original": "[25/May/2026:18:22:45.382 +0530] SECURITY-NEGOTIATION requesterIP=\"127.0.0.1\" instanceName=\"pingdirectory-elastic-test\" threadID=124 conn=0 protocol=\"TLSv1.3\" cipher=\"TLS_AES_256_GCM_SHA384\" clientServerHandshakeTimeMillis=\"87.219\" serverOnlyHandshakeTimeMillis=\"57.181\"", + "timezone": "+0530", + "type": [ + "change" + ] + }, + "observer": { + "name": "pingdirectory-elastic-test" + }, + "ping_directory": { + "ldap_access": { + "client_server_handshake_time_millis": 87.219, + "conn": 0, + "server_only_handshake_time_millis": 57.181, + "thread_id": "124" + } + }, + "related": { + "ip": [ + "127.0.0.1" + ] + }, + "source": { + "ip": "127.0.0.1" + }, + "tls": { + "cipher": "TLS_AES_256_GCM_SHA384", + "version_protocol": "tlsv1.3" + } + }, + { + "@timestamp": "2026-05-25T18:22:45.408+05:30", + "ecs": { + "version": "9.4.0" + }, + "event": { + "action": "bind result", + "category": [ + "iam" + ], + "duration": 7.884, + "kind": "event", + "original": "[25/May/2026:18:22:45.408 +0530] BIND RESULT instanceName=\"pingdirectory-elastic-test\" threadID=10 conn=0 op=0 msgID=1 requesterIP=\"127.0.0.1\" version=\"3\" dn=\"\" authType=\"SIMPLE\" resultCode=0 resultCodeName=\"Success\" qtime=0 etime=7.884 clientConnectionPolicy=\"default\"", + "outcome": "success", + "timezone": "+0530", + "type": [ + "change" + ] + }, + "observer": { + "name": "pingdirectory-elastic-test" + }, + "ping_directory": { + "ldap_access": { + "auth_type": "SIMPLE", + "client_connection_policy": "default", + "conn": 0, + "msg_id": "1", + "op": 0, + "qtime": 0.0, + "result_code": 0, + "result_code_name": "Success", + "thread_id": "10", + "version": "3" + } + }, + "related": { + "ip": [ + "127.0.0.1" + ] + }, + "source": { + "ip": "127.0.0.1" + } + }, + { + "@timestamp": "2026-05-25T18:22:45.416+05:30", + "ecs": { + "version": "9.4.0" + }, + "event": { + "action": "disconnect", + "category": [ + "iam" + ], + "kind": "event", + "original": "[25/May/2026:18:22:45.416 +0530] DISCONNECT requesterIP=\"127.0.0.1\" requesterDN=\"\" instanceName=\"pingdirectory-elastic-test\" threadID=124 conn=0 reason=\"Client Unbind\"", + "reason": "Client Unbind", + "timezone": "+0530", + "type": [ + "change" + ] + }, + "observer": { + "name": "pingdirectory-elastic-test" + }, + "ping_directory": { + "ldap_access": { + "conn": 0, + "thread_id": "124" + } + }, + "related": { + "ip": [ + "127.0.0.1" + ] + }, + "source": { + "ip": "127.0.0.1" + } + }, + { + "@timestamp": "2026-05-25T18:27:23.530+05:30", + "ecs": { + "version": "9.4.0" + }, + "event": { + "action": "extended result", + "category": [ + "iam" + ], + "duration": 3.381, + "kind": "event", + "original": "[25/May/2026:18:27:23.530 +0530] EXTENDED RESULT instanceName=\"pingdirectory-elastic-test\" threadID=29 conn=1 op=0 msgID=1 requesterIP=\"10.50.15.29\" requesterDN=\"\" usingAdminSessionWorkerThread=true requestOID=\"1.3.6.1.4.1.30221.2.6.13\" requestType=\"Start Administrative Session Extended Request\" resultCode=0 resultCodeName=\"Success\" additionalInfo=\"clientName='config-tool' useDedicatedThreadPool=true\" qtime=0 etime=3.381", + "outcome": "success", + "timezone": "+0530", + "type": [ + "change" + ] + }, + "observer": { + "name": "pingdirectory-elastic-test" + }, + "ping_directory": { + "ldap_access": { + "additional_info": "clientName='config-tool'", + "conn": 1, + "msg_id": "1", + "op": 0, + "qtime": 0.0, + "request_oid": "1.3.6.1.4.1.30221.2.6.13", + "request_type": "Start Administrative Session Extended Request", + "result_code": 0, + "result_code_name": "Success", + "thread_id": "29", + "use_dedicated_thread_pool": true, + "using_admin_session_worker_thread": "true" + } + }, + "related": { + "ip": [ + "10.50.15.29" + ] + }, + "source": { + "ip": "10.50.15.29" + } + }, + { + "@timestamp": "2026-05-25T18:27:23.567+05:30", + "ecs": { + "version": "9.4.0" + }, + "event": { + "action": "search result", + "category": [ + "iam" + ], + "duration": 2.145, + "kind": "event", + "original": "[25/May/2026:18:27:23.567 +0530] SEARCH RESULT instanceName=\"pingdirectory-elastic-test\" threadID=29 conn=1 op=2 msgID=3 requesterIP=\"10.50.15.29\" requesterDN=\"cn=Directory Manager,cn=Root DNs,cn=config\" usingAdminSessionWorkerThread=true base=\"cn=System Information,cn=monitor\" scope=0 filter=\"(objectClass=*)\" attrs=\"instanceRoot\" resultCode=0 resultCodeName=\"Success\" qtime=0 etime=2.145 usedPrivileges=\"bypass-acl\" preAuthZUsedPrivileges=\"use-admin-session\" entriesReturned=1", + "outcome": "success", + "timezone": "+0530", + "type": [ + "change" + ] + }, + "observer": { + "name": "pingdirectory-elastic-test" + }, + "ping_directory": { + "ldap_access": { + "attrs": "instanceRoot", + "base": "cn=System Information,cn=monitor", + "conn": 1, + "entries_returned": 1, + "filter": "(objectClass=*)", + "msg_id": "3", + "op": 2, + "pre_auth_zused_privileges": "use-admin-session", + "qtime": 0.0, + "requester_dn": "cn=Directory Manager,cn=Root DNs,cn=config", + "result_code": 0, + "result_code_name": "Success", + "scope": "0", + "thread_id": "29", + "used_privileges": "bypass-acl", + "using_admin_session_worker_thread": "true" + } + }, + "related": { + "ip": [ + "10.50.15.29" + ], + "user": [ + "cn=Directory Manager,cn=Root DNs,cn=config" + ] + }, + "source": { + "ip": "10.50.15.29" + } + }, + { + "@timestamp": "2026-06-23T16:34:12.067+05:30", + "ecs": { + "version": "9.4.0" + }, + "event": { + "action": "search result", + "category": [ + "iam" + ], + "duration": 0.913, + "kind": "event", + "original": "[23/Jun/2026:16:34:12.067 +0530] SEARCH RESULT product=\"Directory Server\" instanceName=\"pingdirectory-elastic-test\" startupID=\"ajDlEQ==\" conn=52 op=1 msgID=2 requesterIP=\"10.50.14.255\" requesterDN=\"cn=Directory Manager,cn=Root DNs,cn=config\" base=\"dc=example,dc=com\" scope=2 filter=\"(objectClass=*)\" attrs=\"ALL\" resultCode=0 resultCodeName=\"Success\" qtime=0 etime=0.913 usedPrivileges=\"bypass-acl\" entriesReturned=12", + "outcome": "success", + "timezone": "+0530", + "type": [ + "change" + ] + }, + "observer": { + "name": "pingdirectory-elastic-test" + }, + "ping_directory": { + "ldap_access": { + "attrs": "ALL", + "base": "dc=example,dc=com", + "conn": 52, + "entries_returned": 12, + "filter": "(objectClass=*)", + "msg_id": "2", + "op": 1, + "product": "Directory Server", + "qtime": 0.0, + "requester_dn": "cn=Directory Manager,cn=Root DNs,cn=config", + "result_code": 0, + "result_code_name": "Success", + "scope": "2", + "startup_id": "ajDlEQ==", + "used_privileges": "bypass-acl" + } + }, + "related": { + "ip": [ + "10.50.14.255" + ], + "user": [ + "cn=Directory Manager,cn=Root DNs,cn=config" + ] + }, + "source": { + "ip": "10.50.14.255" + } + }, + { + "@timestamp": "2026-05-25T18:30:48.688+05:30", + "ecs": { + "version": "9.4.0" + }, + "event": { + "action": "add result", + "category": [ + "iam" + ], + "duration": 24.567, + "kind": "event", + "original": "[25/May/2026:18:30:48.688 +0530] ADD RESULT instanceName=\"pingdirectory-elastic-test\" threadID=9 conn=4 op=1 msgID=2 requesterIP=\"127.0.0.1\" requesterDN=\"cn=Directory Manager,cn=Root DNs,cn=config\" dn=\"ou=People,dc=example,dc=com\" resultCode=0 resultCodeName=\"Success\" qtime=0 etime=24.567 usedPrivileges=\"bypass-acl\"", + "outcome": "success", + "timezone": "+0530", + "type": [ + "change" + ] + }, + "observer": { + "name": "pingdirectory-elastic-test" + }, + "ping_directory": { + "ldap_access": { + "conn": 4, + "dn": "ou=People,dc=example,dc=com", + "msg_id": "2", + "op": 1, + "qtime": 0.0, + "requester_dn": "cn=Directory Manager,cn=Root DNs,cn=config", + "result_code": 0, + "result_code_name": "Success", + "thread_id": "9", + "used_privileges": "bypass-acl" + } + }, + "related": { + "ip": [ + "127.0.0.1" + ], + "user": [ + "ou=People,dc=example,dc=com", + "cn=Directory Manager,cn=Root DNs,cn=config" + ] + }, + "source": { + "ip": "127.0.0.1" + } + }, + { + "@timestamp": "2026-05-25T18:32:55.559+05:30", + "ecs": { + "version": "9.4.0" + }, + "event": { + "action": "add result", + "category": [ + "iam" + ], + "duration": 3.178, + "kind": "event", + "original": "[25/May/2026:18:32:55.559 +0530] ADD RESULT instanceName=\"pingdirectory-elastic-test\" threadID=10 conn=5 op=1 msgID=2 requesterIP=\"127.0.0.1\" requesterDN=\"cn=Directory Manager,cn=Root DNs,cn=config\" dn=\"uid=john.doe,ou=People,dc=example,dc=com\" resultCode=65 resultCodeName=\"Object Class Violation\" message=\"Entry 'uid=john.doe,ou=People,dc=example,dc=com' violates the Directory Server schema configuration because it includes attribute 'department' which is not allowed by any of the object classes defined in that entry\" qtime=1 etime=3.178 usedPrivileges=\"bypass-acl\"", + "outcome": "failure", + "timezone": "+0530", + "type": [ + "change" + ] + }, + "observer": { + "name": "pingdirectory-elastic-test" + }, + "ping_directory": { + "ldap_access": { + "conn": 5, + "dn": "uid=john.doe,ou=People,dc=example,dc=com", + "message": "Entry 'uid=john.doe,ou=People,dc=example,dc=com' violates the Directory Server schema configuration because it includes attribute 'department' which is not allowed by any of the object classes defined in that entry", + "msg_id": "2", + "op": 1, + "qtime": 1.0, + "requester_dn": "cn=Directory Manager,cn=Root DNs,cn=config", + "result_code": 65, + "result_code_name": "Object Class Violation", + "thread_id": "10", + "used_privileges": "bypass-acl" + } + }, + "related": { + "ip": [ + "127.0.0.1" + ], + "user": [ + "uid=john.doe,ou=People,dc=example,dc=com", + "cn=Directory Manager,cn=Root DNs,cn=config" + ] + }, + "source": { + "ip": "127.0.0.1" + } + }, + { + "@timestamp": "2026-05-25T19:29:51.686+05:30", + "ecs": { + "version": "9.4.0" + }, + "event": { + "action": "disconnect", + "category": [ + "iam" + ], + "kind": "event", + "original": "[25/May/2026:19:29:51.686 +0530] DISCONNECT requesterIP=\"172.20.240.130\" requesterDN=\"\" instanceName=\"pingdirectory-elastic-test\" threadID=125 conn=21 reason=\"I/O Error\" msg=\"An error occurred while attempting to read data from the client: SSLException: Unrecognized SSL message, plaintext connection? (SSLEngineInputRecord.java:145 SSLEngineInputRecord.java:64 SSLEngineImpl.java:612 SSLEngineImpl.java:506 SSLEngineImpl.java:482 SSLEngine.java:679 TLSConnectionSecurityProvider.java:1463 LDAPRequestHandler.java:240 DirectoryThread.java:358 (11.0.0.2-20260310181715.000Z-8b5f7f2b))\"", + "reason": "I/O Error", + "timezone": "+0530", + "type": [ + "change" + ] + }, + "observer": { + "name": "pingdirectory-elastic-test" + }, + "ping_directory": { + "ldap_access": { + "conn": 21, + "message": "An error occurred while attempting to read data from the client: SSLException: Unrecognized SSL message, plaintext connection? (SSLEngineInputRecord.java:145 SSLEngineInputRecord.java:64 SSLEngineImpl.java:612 SSLEngineImpl.java:506 SSLEngineImpl.java:482 SSLEngine.java:679 TLSConnectionSecurityProvider.java:1463 LDAPRequestHandler.java:240 DirectoryThread.java:358 (11.0.0.2-20260310181715.000Z-8b5f7f2b))", + "thread_id": "125" + } + }, + "related": { + "ip": [ + "172.20.240.130" + ] + }, + "source": { + "ip": "172.20.240.130" + } + } + ] +} diff --git a/packages/ping_directory/data_stream/ldap_access/_dev/test/system/test-logfile-config.yml b/packages/ping_directory/data_stream/ldap_access/_dev/test/system/test-logfile-config.yml new file mode 100644 index 00000000000..8ec3a97ccb7 --- /dev/null +++ b/packages/ping_directory/data_stream/ldap_access/_dev/test/system/test-logfile-config.yml @@ -0,0 +1,15 @@ +service: ping_directory-logfile-ldap_access +input: filestream +data_stream: + vars: + paths: + - "{{SERVICE_LOGS_DIR}}/*ldap_access*.log" + preserve_original_event: true +numeric_keyword_fields: + - log.file.device_id + - log.file.inode + - log.file.idxhi + - log.file.idxlo + - log.file.vol +assert: + hit_count: 3 diff --git a/packages/ping_directory/data_stream/ldap_access/_dev/test/system/test-udp-config.yml b/packages/ping_directory/data_stream/ldap_access/_dev/test/system/test-udp-config.yml new file mode 100644 index 00000000000..eea06762139 --- /dev/null +++ b/packages/ping_directory/data_stream/ldap_access/_dev/test/system/test-udp-config.yml @@ -0,0 +1,10 @@ +service: ping_directory-udp-ldap_access +service_notify_signal: SIGHUP +input: udp +data_stream: + vars: + listen_address: 0.0.0.0 + listen_port: 9599 + preserve_original_event: true +assert: + hit_count: 3 diff --git a/packages/ping_directory/data_stream/ldap_access/agent/stream/filestream.yml.hbs b/packages/ping_directory/data_stream/ldap_access/agent/stream/filestream.yml.hbs new file mode 100644 index 00000000000..f8cb8e0459c --- /dev/null +++ b/packages/ping_directory/data_stream/ldap_access/agent/stream/filestream.yml.hbs @@ -0,0 +1,25 @@ +paths: +{{#each paths as |path|}} + - {{path}} +{{/each}} +exclude_files: ['\.gz$'] +tags: +{{#if preserve_original_event}} + - preserve_original_event +{{/if}} +{{#each tags as |tag|}} + - {{tag}} +{{/each}} +{{#contains "forwarded" tags}} +publisher_pipeline.disable_host: true +{{/contains}} +{{#if tz_offset}} +fields_under_root: true +fields: + _conf: + tz_offset: "{{tz_offset}}" +{{/if}} +{{#if processors}} +processors: +{{processors}} +{{/if}} diff --git a/packages/ping_directory/data_stream/ldap_access/agent/stream/udp.yml.hbs b/packages/ping_directory/data_stream/ldap_access/agent/stream/udp.yml.hbs new file mode 100644 index 00000000000..4fdea17c509 --- /dev/null +++ b/packages/ping_directory/data_stream/ldap_access/agent/stream/udp.yml.hbs @@ -0,0 +1,24 @@ +host: "{{listen_address}}:{{listen_port}}" +{{#if udp_options}} +{{udp_options}} +{{/if}} +tags: +{{#if preserve_original_event}} + - preserve_original_event +{{/if}} +{{#each tags as |tag|}} + - {{tag}} +{{/each}} +{{#contains "forwarded" tags}} +publisher_pipeline.disable_host: true +{{/contains}} +{{#if tz_offset}} +fields_under_root: true +fields: + _conf: + tz_offset: "{{tz_offset}}" +{{/if}} +{{#if processors}} +processors: +{{processors}} +{{/if}} diff --git a/packages/ping_directory/data_stream/ldap_access/elasticsearch/ingest_pipeline/default.yml b/packages/ping_directory/data_stream/ldap_access/elasticsearch/ingest_pipeline/default.yml new file mode 100644 index 00000000000..c153ce81bb5 --- /dev/null +++ b/packages/ping_directory/data_stream/ldap_access/elasticsearch/ingest_pipeline/default.yml @@ -0,0 +1,645 @@ +--- +description: Pipeline for processing PingDirectory LDAP Access logs. +processors: + - set: + field: ecs.version + tag: set_ecs_version + value: 9.4.0 + - rename: + field: message + tag: rename_message_to_event_original + if: ctx.event?.original == null + target_field: event.original + ignore_missing: true + description: Renames the original `message` field to `event.original` to store a copy of the original message. + - remove: + field: + - message + tag: remove_message + if: ctx.event?.original != null + ignore_missing: true + description: The `message` field is no longer required if the document has an `event.original` field. + - script: + lang: painless + tag: trim_header + source: > + if (ctx.event?.original != null && + ctx.event.original.startsWith("<")) { + int idx = ctx.event.original.indexOf('['); + if (idx > -1) { + ctx.event.original = ctx.event.original.substring(idx); + } + } + - drop: + tag: drop_empty_lines + if: ctx.event?.original == null || ctx.event.original.trim().length() == 0 + - drop: + tag: drop_non_timestamp_lines + if: ctx.event?.original != null && !(ctx.event.original.trim() =~ /^\[\d{2}\/[A-Za-z]{3}\/\d{4}:/) + - grok: + field: event.original + tag: extract_event_original + patterns: + - '\[%{DATA:ping_directory.ldap_access.timestamp} %{ISO8601_TIMEZONE:ping_directory.ldap_access.timezone}\] %{DATA:ping_directory.ldap_access.operation_type} (?=[a-zA-Z][a-zA-Z0-9]*=)%{GREEDYDATA:ping_directory.ldap_access.kvpairs}' + if: ctx.event?.original != null + on_failure: + - append: + field: error.message + tag: append_error_message_for_parse_ldap_access + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - grok: + field: ping_directory.ldap_access.kvpairs + tag: extract_via_field + if: ctx.ping_directory?.ldap_access?.operation_type == 'SEARCH RESULT' + patterns: + - '^(?.*)\s+via="(?[^"]+)"\s+(?.*)$' + ignore_failure: true + - set: + field: ping_directory.ldap_access.kvpairs_without_via + tag: rebuild_kvpairs_without_via + value: '{{{ping_directory.ldap_access.kv_prefix}}} {{{ping_directory.ldap_access.kv_suffix}}}' + if: ctx.ping_directory?.ldap_access?.via != null + - grok: + field: ping_directory.ldap_access.kvpairs + tag: extract_disconnect_msg + if: ctx.ping_directory?.ldap_access?.operation_type == 'DISCONNECT' + patterns: + - '%{GREEDYDATA:ping_directory.ldap_access.kv_prefix} msg="%{GREEDYDATA:ping_directory.ldap_access.msg}"' + ignore_failure: true + - kv: + field: ping_directory.ldap_access.kv_prefix + tag: parsing_kv_prefix + target_field: ping_directory.ldap_access + if: ctx.ping_directory?.ldap_access?.operation_type == 'DISCONNECT' && ctx.ping_directory?.ldap_access?.kv_prefix != null + field_split: ' (?=[A-Za-z][A-Za-z0-9]*=)' + value_split: '=' + trim_value: '"' + ignore_missing: true + - kv: + field: ping_directory.ldap_access.kvpairs + tag: parsing_kvpairs_disconnect_no_msg + target_field: ping_directory.ldap_access + if: ctx.ping_directory?.ldap_access?.operation_type == 'DISCONNECT' && ctx.ping_directory?.ldap_access?.kv_prefix == null + field_split: ' (?=[A-Za-z][A-Za-z0-9]*=)' + value_split: '=' + trim_value: '"' + ignore_missing: true + - kv: + field: ping_directory.ldap_access.kvpairs + tag: parsing_kvpairs + target_field: ping_directory.ldap_access + if: ctx.ping_directory?.ldap_access?.operation_type != 'DISCONNECT' && (ctx.ping_directory?.ldap_access?.operation_type != 'SEARCH RESULT' || ctx.ping_directory?.ldap_access?.via == null) + field_split: ' (?=[A-Za-z][A-Za-z0-9]*=)' + value_split: '=' + trim_value: '"' + ignore_missing: true + - grok: + field: ping_directory.ldap_access.via + tag: parse_via_field + if: ctx.ping_directory?.ldap_access?.via != null && ctx.ping_directory.ldap_access.via != '' + patterns: + - "app='%{DATA:ping_directory.ldap_access.via_detail.app}' clientIP='%{DATA:ping_directory.ldap_access.via_detail.client_ip}' sessionID='%{DATA:ping_directory.ldap_access.via_detail.session_id}' requestID='%{DATA:ping_directory.ldap_access.via_detail.request_id}'" + on_failure: + - append: + field: error.message + tag: append_error_message_for_parse_via_field + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - kv: + field: ping_directory.ldap_access.kvpairs_without_via + tag: parsing_kvpairs_kvpairs_without_via + target_field: ping_directory.ldap_access + if: ctx.ping_directory?.ldap_access?.via != null + field_split: ' (?=[A-Za-z][A-Za-z0-9]*=)' + value_split: '=' + trim_value: '"' + ignore_missing: true + - remove: + field: ping_directory.ldap_access.kv_prefix + tag: remove_pingdirectory_kv_prefix + ignore_missing: true + - remove: + field: ping_directory.ldap_access.kv_suffix + tag: remove_pingdirectory_kv_suffix + ignore_missing: true + - remove: + field: ping_directory.ldap_access.kvpairs_without_via + tag: remove_pingdirectory_kvpairs_without_via + ignore_missing: true + - remove: + field: ping_directory.ldap_access.via + tag: remove_pingdirectory_via + ignore_missing: true + - remove: + field: ping_directory.ldap_access.kvpairs + tag: remove_pingdirectory_kvpairs + ignore_missing: true + - script: + lang: painless + tag: rename_camel_case_to_snake_case + description: Convert all camelCase field names in ping_directory.ldap_access to snake_case. + source: |- + def ldap = ctx.ping_directory?.ldap_access; + if (ldap == null) return; + List keys = new ArrayList(ldap.keySet()); + for (String key : keys) { + if (key.equals(key.toLowerCase())) continue; + String snake = ""; + for (int i = 0; i < key.length(); i++) { + String ch = key.substring(i, i + 1); + String lower = ch.toLowerCase(); + if (!ch.equals(lower) && i > 0 && key.substring(i - 1, i).equals(key.substring(i - 1, i).toLowerCase())) { + snake += "_"; + } + snake += lower; + } + if (!snake.equals(key)) { + def val = ldap.remove(key); + ldap.put(snake, val); + } + } + - set: + field: event.kind + tag: set_event_kind + value: event + - append: + field: event.category + tag: append_iam_into_event_category + value: iam + - append: + field: event.type + tag: append_change_into_event_type + value: change + - append: + field: related.user + tag: append_ldap_access_auth_dn_into_related_user + if: ctx.ping_directory?.ldap_access?.auth_dn != null + value: '{{{ping_directory.ldap_access.auth_dn}}}' + allow_duplicates: false + - append: + field: related.user + tag: append_ldap_access_dn_into_related_user + if: ctx.ping_directory?.ldap_access?.dn != null + value: '{{{ping_directory.ldap_access.dn}}}' + allow_duplicates: false + - set: + field: tls.cipher + tag: set_tls_cipher_from_ldap_access_cipher + copy_from: ping_directory.ldap_access.cipher + ignore_empty_value: true + - convert: + field: ping_directory.ldap_access.client_server_handshake_time_millis + tag: convert_clientServerHandshakeTimeMillis_to_float + if: ctx.ping_directory?.ldap_access?.client_server_handshake_time_millis != '' + type: float + ignore_missing: true + on_failure: + - append: + field: error.message + tag: append_error_message_for_convert_clientServerHandshakeTimeMillis_to_float + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - convert: + field: ping_directory.ldap_access.conn + tag: convert_conn_to_long + type: long + ignore_missing: true + on_failure: + - append: + field: error.message + tag: append_error_message_for_convert_conn_to_long + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - convert: + field: ping_directory.ldap_access.entries_returned + tag: convert_entriesReturned_to_long + type: long + ignore_missing: true + on_failure: + - append: + field: error.message + tag: append_error_message_for_convert_entriesReturned_to_long + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - convert: + field: ping_directory.ldap_access.etime + tag: convert_etime_to_float + if: ctx.ping_directory?.ldap_access?.etime != '' + type: float + ignore_missing: true + on_failure: + - append: + field: error.message + tag: append_error_message_for_convert_etime_to_float + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - set: + field: event.duration + tag: set_event_duration_from_ldap_access_etime + copy_from: ping_directory.ldap_access.etime + ignore_empty_value: true + - convert: + field: ping_directory.ldap_access.from + tag: convert_from_to_ip + if: ctx.ping_directory?.ldap_access?.from != '' + type: ip + ignore_missing: true + on_failure: + - append: + field: error.message + tag: append_error_message_for_convert_from_to_ip + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - set: + field: source.ip + tag: set_source_ip_from_ldap_access_from + copy_from: ping_directory.ldap_access.from + ignore_empty_value: true + - append: + field: related.ip + tag: append_ldap_access_from_into_related_ip + if: ctx.ping_directory?.ldap_access?.from != null + value: '{{{ping_directory.ldap_access.from}}}' + allow_duplicates: false + - convert: + field: ping_directory.ldap_access.requester_ip + tag: convert_requester_ip_to_ip + type: ip + ignore_missing: true + description: Validates/normalizes requester_ip in place; values like "internal" that are not valid IPs are moved to requester_ip_string. + on_failure: + - rename: + field: ping_directory.ldap_access.requester_ip + tag: rename_requester_ip_to_requester_ip_string + target_field: ping_directory.ldap_access.requester_ip_string + ignore_missing: true + - grok: + field: ping_directory.ldap_access.requester_ip + tag: validate_requester_ip + patterns: + - '^%{IP:ping_directory.ldap_access.requester_ip_valid}$' + ignore_missing: true + ignore_failure: true + - set: + field: source.ip + tag: set_source_ip_from_ldap_access_requester_ip + copy_from: ping_directory.ldap_access.requester_ip_valid + ignore_empty_value: true + override: false + - append: + field: related.ip + tag: append_ldap_access_requester_ip_into_related_ip + if: ctx.ping_directory?.ldap_access?.requester_ip_valid != null + value: '{{{ping_directory.ldap_access.requester_ip_valid}}}' + allow_duplicates: false + - remove: + field: ping_directory.ldap_access.requester_ip_valid + tag: remove_ping_directory_ldap_access_requester_ip_valid_tmp + ignore_missing: true + - convert: + field: ping_directory.ldap_access.from_port + tag: convert_fromPort_to_long + type: long + ignore_missing: true + on_failure: + - append: + field: error.message + tag: append_error_message_for_convert_fromPort_to_long + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - set: + field: source.port + tag: set_source_port_from_ldap_access_from_port + copy_from: ping_directory.ldap_access.from_port + ignore_empty_value: true + - set: + field: observer.name + tag: set_observer_name_from_ldap_access_instance_name + copy_from: ping_directory.ldap_access.instance_name + ignore_empty_value: true + - rename: + field: ping_directory.ldap_access.msg + tag: rename_msg_to_message + target_field: ping_directory.ldap_access.message + ignore_missing: true + - convert: + field: ping_directory.ldap_access.msg_id + tag: convert_msgID_to_long + type: long + ignore_missing: true + on_failure: + - append: + field: error.message + tag: append_error_message_for_convert_msgID_to_long + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - convert: + field: ping_directory.ldap_access.msg_id + tag: convert_msg_id_to_keyword + type: string + ignore_missing: true + on_failure: + - append: + field: error.message + tag: append_error_message_for_convert_msg_id_to_keyword + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - convert: + field: ping_directory.ldap_access.op + tag: convert_op_to_long + type: long + ignore_missing: true + on_failure: + - append: + field: error.message + tag: append_error_message_for_convert_op_to_long + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - convert: + field: ping_directory.ldap_access.qtime + tag: convert_qtime_to_float + if: ctx.ping_directory?.ldap_access?.qtime != '' + type: float + ignore_missing: true + on_failure: + - append: + field: error.message + tag: append_error_message_for_convert_qtime_to_float + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - append: + field: related.user + tag: append_ldap_access_requester_dn_into_related_user + if: ctx.ping_directory?.ldap_access?.requester_dn != null + value: '{{{ping_directory.ldap_access.requester_dn}}}' + allow_duplicates: false + - convert: + field: ping_directory.ldap_access.result_code + tag: convert_resultCode_to_long + type: long + ignore_missing: true + on_failure: + - append: + field: error.message + tag: append_error_message_for_convert_resultCode_to_long + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - convert: + field: ping_directory.ldap_access.server_only_handshake_time_millis + tag: convert_serverOnlyHandshakeTimeMillis_to_float + if: ctx.ping_directory?.ldap_access?.server_only_handshake_time_millis != '' + type: float + ignore_missing: true + on_failure: + - append: + field: error.message + tag: append_error_message_for_convert_serverOnlyHandshakeTimeMillis_to_float + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - convert: + field: ping_directory.ldap_access.thread_id + tag: convert_threadID_to_long + type: long + ignore_missing: true + on_failure: + - append: + field: error.message + tag: append_error_message_for_convert_threadID_to_long + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - convert: + field: ping_directory.ldap_access.thread_id + tag: convert_thread_id_to_keyword + if: ctx.ping_directory?.ldap_access?.thread_id != '' + type: string + ignore_missing: true + on_failure: + - append: + field: error.message + tag: append_error_message_for_convert_thread_id_to_keyword + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - set: + field: event.timezone + tag: set_event_timezone_from_ldap_access_timezone + copy_from: ping_directory.ldap_access.timezone + ignore_empty_value: true + - set: + field: event.timezone + tag: set_event_timezone_from_tz_offset + copy_from: _conf.tz_offset + ignore_empty_value: true + override: true + - date: + field: ping_directory.ldap_access.timestamp + tag: date_timestamp + target_field: ping_directory.ldap_access.timestamp + formats: + - dd/MMM/yyyy:HH:mm:ss.SSS + if: ctx.ping_directory?.ldap_access?.timestamp != null && ctx.ping_directory.ldap_access.timestamp != '' && ctx.event?.timezone == null + on_failure: + - append: + field: error.message + tag: append_error_message_for_date_timestamp + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - date: + field: ping_directory.ldap_access.timestamp + tag: date_timestamp_with_timezone + target_field: ping_directory.ldap_access.timestamp + timezone: '{{{event.timezone}}}' + formats: + - dd/MMM/yyyy:HH:mm:ss.SSS + if: ctx.ping_directory?.ldap_access?.timestamp != null && ctx.ping_directory.ldap_access.timestamp != '' && ctx.event?.timezone != null + on_failure: + - append: + field: error.message + tag: append_error_message_for_date_timestamp_with_timezone + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - set: + field: '@timestamp' + tag: set_@timestamp_from_ldap_access_timestamp + copy_from: ping_directory.ldap_access.timestamp + ignore_empty_value: true + - convert: + field: ping_directory.ldap_access.to + tag: convert_to_to_ip + if: ctx.ping_directory?.ldap_access?.to != '' + type: ip + ignore_missing: true + on_failure: + - append: + field: error.message + tag: append_error_message_for_convert_to_to_ip + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - set: + field: destination.ip + tag: set_destination_ip_from_ldap_access_to + copy_from: ping_directory.ldap_access.to + ignore_empty_value: true + - append: + field: related.ip + tag: append_ldap_access_to_into_related_ip + if: ctx.ping_directory?.ldap_access?.to != null + value: '{{{ping_directory.ldap_access.to}}}' + allow_duplicates: false + - convert: + field: ping_directory.ldap_access.to_port + tag: convert_toPort_to_long + type: long + ignore_missing: true + on_failure: + - append: + field: error.message + tag: append_error_message_for_convert_toPort_to_long + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - set: + field: destination.port + tag: set_destination_port_from_ldap_access_to_port + copy_from: ping_directory.ldap_access.to_port + ignore_empty_value: true + - set: + field: event.reason + tag: set_event_reason_from_ldap_access_disconnect_reason + copy_from: ping_directory.ldap_access.reason + ignore_empty_value: true + - set: + field: event.reason + tag: set_event_reason_from_ldap_access_auth_failure_reason + copy_from: ping_directory.ldap_access.auth_failure_reason + ignore_empty_value: true + override : false + - convert: + field: ping_directory.ldap_access.use_dedicated_thread_pool + tag: convert_use_dedicated_thread_pool_to_boolean + if: ctx.ping_directory?.ldap_access?.use_dedicated_thread_pool != '' + type: boolean + ignore_missing: true + on_failure: + - append: + field: error.message + tag: append_error_message_for_convert_use_dedicated_thread_pool_to_boolean + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - set: + field: trace.id + tag: set_trace_id_from_correlation_id + copy_from: ping_directory.ldap_access.correlation_id + ignore_empty_value: true + - convert: + field: ping_directory.ldap_access.via_detail.client_ip + tag: convert_client_ip_to_ip + if: ctx.ping_directory?.ldap_access?.via_detail?.client_ip != null + type: ip + ignore_missing: true + on_failure: + - append: + field: error.message + tag: append_error_message_for_convert_via_detail_client_ip_to_ip + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - append: + field: related.ip + tag: append_via_detail_client_ip_into_related_ip + if: ctx.ping_directory?.ldap_access?.via_detail?.client_ip != null + value: '{{{ping_directory.ldap_access.via_detail.client_ip}}}' + allow_duplicates: false + - set: + field: event.action + tag: set_event_action_from_operation_type + copy_from: ping_directory.ldap_access.operation_type + ignore_empty_value: true + - lowercase: + field: event.action + tag: lowercase_event_action + if: ctx.event?.action != null + ignore_missing: true + - script: + lang: painless + tag: set_event_outcome_from_result_code_name + if: ctx.ping_directory?.ldap_access?.result_code_name != null + source: > + String name = ctx.ping_directory.ldap_access.result_code_name; + ctx.event.outcome = name.equalsIgnoreCase('Success') ? 'success' : 'failure'; + - set: + field: network.protocol + tag: set_network_protocol_from_ldap_access_protocol + copy_from: ping_directory.ldap_access.protocol + if: ctx.ping_directory?.ldap_access?.operation_type == 'CONNECT' + ignore_empty_value: true + - lowercase: + field: network.protocol + tag: lowercase_network_protocol + if: ctx.network?.protocol != null + ignore_missing: true + - set: + field: tls.version_protocol + tag: set_protocol_from_tls_protocol + if: ctx.ping_directory?.ldap_access?.operation_type == 'SECURITY-NEGOTIATION' + copy_from: ping_directory.ldap_access.protocol + ignore_empty_value: true + - lowercase: + field: tls.version_protocol + tag: lowercase_tls_version_protocol + if: ctx.tls?.version_protocol != null + ignore_missing: true + - set: + field: http.request.id + tag: set_http_request_id + copy_from: ping_directory.ldap_access.http_request_id + ignore_empty_value: true + - remove: + field: + - ping_directory.ldap_access.requester_ip + - ping_directory.ldap_access.cn + - ping_directory.ldap_access.http_request_id + - ping_directory.ldap_access.correlation_id + - ping_directory.ldap_access.auth_failure_reason + - ping_directory.ldap_access.protocol + - ping_directory.ldap_access.operation_type + - ping_directory.ldap_access.cipher + - ping_directory.ldap_access.reason + - ping_directory.ldap_access.etime + - ping_directory.ldap_access.from + - ping_directory.ldap_access.from_port + - ping_directory.ldap_access.instance_name + - ping_directory.ldap_access.msg + - ping_directory.ldap_access.timestamp + - ping_directory.ldap_access.timezone + - ping_directory.ldap_access.to + - ping_directory.ldap_access.to_port + tag: remove_fields_mapped_to_ecs + ignore_missing: true + - script: + tag: remove_null_values + lang: painless + description: Remove null or empty values from the document. + source: |- + void handleMap(Map map) { + map.values().removeIf(v -> { + if (v instanceof Map) { + handleMap(v); + } else if (v instanceof List) { + handleList(v); + } + return v == null || v == '' || (v instanceof Map && v.size() == 0) || (v instanceof List && v.size() == 0) + }); + } + void handleList(List list) { + list.removeIf(v -> { + if (v instanceof Map) { + handleMap(v); + } else if (v instanceof List) { + handleList(v); + } + return v == null || v == '' || (v instanceof Map && v.size() == 0) || (v instanceof List && v.size() == 0) + }); + } + handleMap(ctx); + - append: + field: tags + tag: append_preserve_original_event_on_error + value: preserve_original_event + allow_duplicates: false + if: ctx.error?.message != null +on_failure: + - append: + field: error.message + tag: append_error_message_on_failure + value: >- + Processor {{{_ingest.on_failure_processor_type}}} + {{{#_ingest.on_failure_processor_tag}}}with tag '{{{_ingest.on_failure_processor_tag}}}' + {{{/_ingest.on_failure_processor_tag}}} + in pipeline '{{{_ingest.pipeline}}}' + failed with message '{{{_ingest.on_failure_message}}}' + - set: + field: event.kind + tag: set_event_kind_to_pipeline_error + value: pipeline_error + - append: + field: tags + tag: append_tags + value: preserve_original_event + allow_duplicates: false diff --git a/packages/ping_directory/data_stream/ldap_access/fields/base-fields.yml b/packages/ping_directory/data_stream/ldap_access/fields/base-fields.yml new file mode 100644 index 00000000000..202ab23a529 --- /dev/null +++ b/packages/ping_directory/data_stream/ldap_access/fields/base-fields.yml @@ -0,0 +1,25 @@ +- name: data_stream.dataset + external: ecs + description: Dataset name associated with the data stream. +- name: data_stream.namespace + external: ecs + description: Namespace used to group related data streams. +- name: data_stream.type + external: ecs + description: Type of data stream, such as logs or metrics. +- name: event.dataset + type: constant_keyword + external: ecs + value: ping_directory.ldap_access + description: Identifies the PingDirectory LDAP access log dataset. +- name: event.module + type: constant_keyword + external: ecs + value: ping_directory + description: Module that generated the event. +- name: log.source.address + type: keyword + description: Source address from which the log event was read / sent from. +- name: '@timestamp' + external: ecs + description: Date and time when the event occurred. diff --git a/packages/ping_directory/data_stream/ldap_access/fields/beats.yml b/packages/ping_directory/data_stream/ldap_access/fields/beats.yml new file mode 100644 index 00000000000..1a4c37ca5c8 --- /dev/null +++ b/packages/ping_directory/data_stream/ldap_access/fields/beats.yml @@ -0,0 +1,27 @@ +- name: input.type + type: keyword + description: Type of filebeat input. +- name: log.offset + type: long + description: Log offset. +- name: log.file + type: group + fields: + - name: device_id + type: keyword + description: ID of the device containing the filesystem where the file resides. + - name: fingerprint + type: keyword + description: The sha256 fingerprint identity of the file when fingerprinting is enabled. + - name: idxhi + type: keyword + description: The high-order part of a unique identifier that is associated with a file. (Windows-only). + - name: idxlo + type: keyword + description: The low-order part of a unique identifier that is associated with a file. (Windows-only). + - name: inode + type: keyword + description: Inode number of the log file. + - name: vol + type: keyword + description: The serial number of the volume that contains a file. (Windows-only). diff --git a/packages/ping_directory/data_stream/ldap_access/fields/ecs.yml b/packages/ping_directory/data_stream/ldap_access/fields/ecs.yml new file mode 100644 index 00000000000..cb46bd0df40 --- /dev/null +++ b/packages/ping_directory/data_stream/ldap_access/fields/ecs.yml @@ -0,0 +1,10 @@ +- name: observer.product + external: ecs + type: constant_keyword + value: PingDirectory + description: The product name of the observer that generated the event. +- name: observer.vendor + external: ecs + type: constant_keyword + value: PingIdentity + description: The vendor name of the observer that generated the event. diff --git a/packages/ping_directory/data_stream/ldap_access/fields/fields.yml b/packages/ping_directory/data_stream/ldap_access/fields/fields.yml new file mode 100644 index 00000000000..4b9de69d536 --- /dev/null +++ b/packages/ping_directory/data_stream/ldap_access/fields/fields.yml @@ -0,0 +1,150 @@ +- name: ping_directory + type: group + fields: + - name: ldap_access + type: group + fields: + - name: additional_info + type: keyword + description: Additional diagnostic information returned with the extended operation result. + - name: attrs + type: text + description: Requested attributes in the search. Empty means all user attributes returned. + - name: auth_dn + type: keyword + description: Fully-resolved DN of the authenticated user after bind. May differ from bind dn. + - name: auth_failure_id + type: keyword + description: Identifier associated with the authentication failure. + - name: auth_failure_name + type: keyword + description: Human-readable name of the authentication failure condition. + - name: auth_type + type: keyword + description: Authentication mechanism used in the Bind request. + - name: base + type: keyword + description: Base DN of the LDAP search operation. + - name: client_connection_policy + type: keyword + description: Name of the client connection policy applied to this connection. + - name: client_ip + type: ip + description: Client IP value recorded by PingDirectory for the operation. + - name: client_server_handshake_time_millis + type: float + description: Total time in ms for the full client-server TLS handshake. + - name: code_location + type: keyword + description: Internal code location where the operation or event originated. + - name: conn + type: long + description: LDAP connection ID. Each TCP connection from a client gets a unique conn value. + - name: dn + type: keyword + description: DN of the entry that was added or modified in the directory. + - name: entries_returned + type: long + description: Number of LDAP entries returned in the search result. + - name: filter + type: keyword + description: LDAP search filter expression used in the search request. + - name: matched_dn + type: keyword + description: DN that matched the LDAP request during processing. + - name: message + type: text + description: Message text from a DISCONNECT operation. + - name: msg_id + type: keyword + description: LDAP message ID from the protocol request. Used to correlate request/response. + - name: op + type: long + description: Operation number within the connection. Increments per operation on the same conn. + - name: op_purpose + type: keyword + description: Application name, version, and code location that triggered the modify. + - name: origin + type: keyword + description: Origin from which the request was initiated. + - name: pre_auth_zused_privileges + type: keyword + description: Privileges used before authorization checks, such as admin session privileges. + - name: product + type: keyword + description: Product name associated with the operation or certificate information. + - name: qtime + type: float + description: Time in milliseconds the operation waited in the queue before being processed. + - name: request_controls + type: keyword + description: OIDs of LDAP controls attached to the modify request. + - name: request_id + type: keyword + description: Unique identifier assigned to the request. + - name: request_oid + type: keyword + description: OID identifying the specific LDAP extended operation requested. + - name: request_type + type: keyword + description: Human-readable name of the extended operation type derived from the OID. + - name: requester_dn + type: keyword + description: Distinguished Name of the authenticated user making the request. + - name: requester_ip_string + type: keyword + description: Raw value of the client identifier when it is not a valid IP address (e.g. "internal"). + - name: result_code + type: long + description: LDAP result code numeric value. 0=Success. See RFC 4511 for full list. + - name: result_code_name + type: keyword + description: Human-readable name of the LDAP result code (e.g., Success, NoSuchObject). + - name: sasl_mechanism + type: keyword + description: SASL authentication mechanism used for the bind operation. + - name: scope + type: byte + description: 'LDAP search scope: 0=baseObject, 1=singleLevel, 2=wholeSubtree.' + - name: server_only_handshake_time_millis + type: float + description: Time in ms for the server-only portion of the TLS handshake. + - name: session_id + type: keyword + description: Identifier associated with the client session. + - name: startup_id + type: keyword + description: Identifier associated with the server startup instance. + - name: streamed_entries_from_index + type: keyword + description: Number of entries streamed directly from an index during search processing. + - name: thread_id + type: keyword + description: ID of the server thread that handled the LDAP operation. + - name: use_dedicated_thread_pool + type: boolean + description: Indicates whether a dedicated thread pool was used to process the operation. + - name: used_privileges + type: keyword + description: Server privileges used to process the operation (e.g., bypass-acl, config-read). + - name: using_admin_session_worker_thread + type: boolean + description: Whether the operation used a dedicated admin session worker thread. + - name: version + type: keyword + description: LDAP protocol version used in the Bind request (always 3 for LDAPv3). + - name: via_detail + type: group + fields: + - name: app + type: keyword + description: Application name extracted from the via field. + - name: client_ip + type: ip + description: Client IP extracted from the via field. + - name: request_id + type: keyword + description: Request ID extracted from the via field. + - name: session_id + type: keyword + description: Session ID extracted from the via field. diff --git a/packages/ping_directory/data_stream/ldap_access/manifest.yml b/packages/ping_directory/data_stream/ldap_access/manifest.yml new file mode 100644 index 00000000000..54e42c284fa --- /dev/null +++ b/packages/ping_directory/data_stream/ldap_access/manifest.yml @@ -0,0 +1,116 @@ +title: LDAP Access +type: logs +streams: + - input: udp + enabled: false + template_path: udp.yml.hbs + title: LDAP Access logs + description: Collect PingDirectory LDAP Access logs via syslog over UDP. + vars: + - name: listen_address + type: text + title: Listen Address + description: The bind address to listen for UDP connections. Set to `0.0.0.0` to bind to all available interfaces. + multi: false + required: true + show_user: true + default: localhost + - name: listen_port + type: integer + title: Listen Port + description: The UDP port number to listen on. + multi: false + required: true + show_user: true + default: 9602 + - name: tz_offset + type: text + title: Timezone Offset + multi: false + required: false + show_user: true + description: >- + When interpreting syslog timestamps without a time zone, use this timezone offset. Datetimes recorded in logs are by default interpreted in relation to the timezone set up on the host where the agent is operating. Use this parameter to adjust the timezone offset when importing logs from a host in a different timezone so that datetimes are appropriately interpreted. Both a canonical ID (such as 'Europe/Amsterdam') and an HH:mm differential (such as '-05:00') are acceptable timezone formats. + - name: udp_options + type: yaml + title: Custom UDP Options + multi: false + required: false + show_user: false + default: | + #max_message_size: 50KiB + #timeout: 300s + description: Specify custom configuration options for the UDP input. + - name: tags + type: text + title: Tags + multi: true + required: true + show_user: false + default: + - forwarded + - ping_directory-audit + - name: preserve_original_event + required: true + show_user: true + title: Preserve original event + description: Preserves a raw copy of the original event, added to the field `event.original`. + type: bool + multi: false + default: false + - name: processors + type: yaml + title: Processors + multi: false + required: false + show_user: false + description: >- + Processors are used to reduce the number of fields in the exported event or to enhance the event with metadata. This executes in the agent before the logs are parsed. See [Processors](https://www.elastic.co/guide/en/beats/filebeat/current/filtering-and-enhancing-data.html) for details. + - input: filestream + enabled: false + title: LDAP Access + description: Collect logs with filestream. + template_path: filestream.yml.hbs + vars: + - name: paths + type: text + title: Paths + multi: true + required: true + show_user: true + default: + - /opt/pingdirectory/logs/access* + description: A list of glob-based paths that will be crawled and fetched. + - name: tz_offset + type: text + title: Timezone Offset + multi: false + required: false + show_user: true + description: >- + When interpreting syslog timestamps without a time zone, use this timezone offset. Datetimes recorded in logs are by default interpreted in relation to the timezone set up on the host where the agent is operating. Use this parameter to adjust the timezone offset when importing logs from a host in a different timezone so that datetimes are appropriately interpreted. Both a canonical ID (such as 'Europe/Amsterdam') and an HH:mm differential (such as '-05:00') are acceptable timezone formats. + - name: tags + type: text + title: Tags + multi: true + required: true + show_user: false + default: + - forwarded + - ping_directory-audit + - name: preserve_original_event + required: true + show_user: true + title: Preserve original event + description: Preserves a raw copy of the original event, added to the field `event.original`. + type: bool + multi: false + default: false + - name: processors + type: yaml + title: Processors + multi: false + required: false + show_user: false + description: >- + Processors are used to reduce the number of fields in the exported event or to enhance the event with metadata. This executes in the agent before the logs are parsed. See [Processors](https://www.elastic.co/guide/en/beats/filebeat/current/filtering-and-enhancing-data.html) for details. diff --git a/packages/ping_directory/data_stream/ldap_access/sample_event.json b/packages/ping_directory/data_stream/ldap_access/sample_event.json new file mode 100644 index 00000000000..4db1c3f328f --- /dev/null +++ b/packages/ping_directory/data_stream/ldap_access/sample_event.json @@ -0,0 +1,85 @@ +{ + "@timestamp": "2026-05-25T18:30:48.688+05:30", + "agent": { + "ephemeral_id": "21e8bfb6-0fc0-4cae-85cb-927ca9209d57", + "id": "b55cf73b-98dc-476e-b895-6d7d0fee76e6", + "name": "elastic-agent-26139", + "type": "filebeat", + "version": "8.18.0" + }, + "data_stream": { + "dataset": "ping_directory.ldap_access", + "namespace": "66896", + "type": "logs" + }, + "ecs": { + "version": "9.4.0" + }, + "elastic_agent": { + "id": "b55cf73b-98dc-476e-b895-6d7d0fee76e6", + "snapshot": false, + "version": "8.18.0" + }, + "event": { + "action": "add result", + "agent_id_status": "verified", + "category": [ + "iam" + ], + "dataset": "ping_directory.ldap_access", + "duration": 24.567, + "ingested": "2026-07-03T07:12:26Z", + "kind": "event", + "original": "[25/May/2026:18:30:48.688 +0530] ADD RESULT instanceName=\"pingdirectory-elastic-test\" threadID=9 conn=4 op=1 msgID=2 requesterIP=\"127.0.0.1\" requesterDN=\"cn=Directory Manager,cn=Root DNs,cn=config\" dn=\"ou=People,dc=example,dc=com\" resultCode=0 resultCodeName=\"Success\" qtime=0 etime=24.567 usedPrivileges=\"bypass-acl\"", + "outcome": "success", + "timezone": "+0530", + "type": [ + "change" + ] + }, + "input": { + "type": "filestream" + }, + "log": { + "file": { + "device_id": "64768", + "inode": "2492551", + "path": "/tmp/service_logs/test-ldap_access.log" + }, + "offset": 0 + }, + "observer": { + "name": "pingdirectory-elastic-test" + }, + "ping_directory": { + "ldap_access": { + "conn": 4, + "dn": "ou=People,dc=example,dc=com", + "msg_id": "2", + "op": 1, + "qtime": 0, + "requester_dn": "cn=Directory Manager,cn=Root DNs,cn=config", + "result_code": 0, + "result_code_name": "Success", + "thread_id": "9", + "used_privileges": "bypass-acl" + } + }, + "related": { + "ip": [ + "127.0.0.1" + ], + "user": [ + "ou=People,dc=example,dc=com", + "cn=Directory Manager,cn=Root DNs,cn=config" + ] + }, + "source": { + "ip": "127.0.0.1" + }, + "tags": [ + "preserve_original_event", + "forwarded", + "ping_directory-audit" + ] +} diff --git a/packages/ping_directory/docs/README.md b/packages/ping_directory/docs/README.md new file mode 100644 index 00000000000..4e195272403 --- /dev/null +++ b/packages/ping_directory/docs/README.md @@ -0,0 +1,294 @@ +# PingDirectory Integration for Elastic + +## Overview + +[PingDirectory](https://www.pingidentity.com/en/product/pingdirectory.html) is an **enterprise-grade LDAP directory server** and identity data store. It provides high-performance, scalable directory services for managing user identities, credentials, and access control across hybrid environments — combining authentication, authorization, and directory data management into a unified platform for **critical identity infrastructure**. + +This integration collects data from PingDirectory log files using the Elastic Agent filestream input, or over the network using the Elastic Agent UDP input. It provides visibility into LDAP connection activity, requests, results, and security negotiation events across your PingDirectory environment. + +### Compatibility + +The PingDirectory integration is compatible with **PingDirectory version 11.0.0.2 and above**. + +### How it works + +The integration uses the Elastic Agent filestream input to collect log files generated by PingDirectory on a configurable path, or the UDP input to receive logs forwarded by a PingDirectory Syslog Text Access Log Publisher. Each collection cycle: + +1. Reads log entries from the configured PingDirectory LDAP Access log file (`access.log`), or receives them over UDP when syslog forwarding is used. +2. Parses each log line using a grok pattern to extract fields such as timestamp, connection ID, operation type, instance name, client and server IP/port, requester DN, and result code. +3. Extracts operation-specific details including request type, search filters, response time, and result codes from the access log record. +4. Emits each log entry as an individual event for ingestion and enrichment via the built-in ingest pipeline. + +## What data does this integration collect? + +The PingDirectory integration collects the following types of data: + +| Data stream | Description | +|---|---| +| `ldap_access` | LDAP access logs generated by PingDirectory, including connection and disconnection events, LDAP requests and results, security negotiation details, client and server addresses, requester identities, and response times for monitoring LDAP client activity across your directory environment. + +### Supported use cases + +* **LDAP connection monitoring**: Track connect, disconnect, and security negotiation events to gain visibility into client connection activity and TLS/cipher usage across your directory environment. + +* **Operational troubleshooting and access analysis**: Analyze who performed which LDAP operations, from which client IP, with what result code, and at what response time to investigate failed binds, slow searches, and unauthorized access attempts. + +## What do I need to use this integration? + +### From PingDirectory + +* **PingDirectory deployment**: An active PingDirectory server configured to generate LDAP Access logs. +* **Access logging enabled**: The File-Based Access Logger must be enabled to record LDAP operations, or a Syslog Text Access Log Publisher must be configured to forward access logs over UDP. To configure the publisher: in the PingDirectory Administrative Console, go to **Configuration → Log Publishers → New Log Publisher → Syslog Text Access Log Publisher**, create a **Syslog External Server** with the Elastic Agent host and UDP port (must match the integration's **Listen Port**, default `9602`), then enable and save the publisher. +* **Log access**: Elastic Agent must have access to the Access log files on the PingDirectory host, or network access to receive the forwarded syslog UDP traffic. +* **Elastic Agent**: Version 8.18+ or 9.0+ with Fleet enrollment. + +## How do I deploy this integration? + +### Agent-based deployment + +Elastic Agent must be installed. For more details, check the Elastic Agent [installation instructions](docs-content://reference/fleet/install-elastic-agents.md). You can install only one Elastic Agent per host. + +Elastic Agent is required to stream data from the syslog or log file receiver and ship the data to Elastic, where the events will then be processed via the integration's ingest pipelines. + +### Configure + +1. In Kibana, navigate to **Fleet → Integrations** and search for **PingDirectory**. +2. Click **Add PingDirectory**. +3. Configure the integration settings: + + * To collect from a local log file, enable the filestream input and specify the **Paths** to the PingDirectory LDAP Access log file(s), for example: + /opt/pingdirectory/logs/access* + * To receive logs forwarded over the network, enable the UDP input and set the **Listen Address** and **Listen Port** to match the Syslog External Server configured on PingDirectory. + * Configure any optional collection settings as required. +4. Select **Save and continue** to save the integration. +5. Add the integration to an existing Agent policy or create a new one. +6. Verify that LDAP Access events are being ingested into Elasticsearch. + +### Validation + +#### Dashboard populated + +1. In the top search bar in Kibana, search for **Dashboards**. +2. In the search bar, type **PingDirectory**. +3. Open the **[Logs PingDirectory] LDAP Access** dashboard. +4. Verify that the visualizations are populated with LDAP access data, including connection events, requester identities, result codes, and client IP addresses. + +## Scaling + +For more information on architectures that can be used for scaling this integration, check the [Ingest Architectures](https://www.elastic.co/docs/manage-data/ingest/ingest-reference-architectures) documentation. + +## Troubleshooting + +* **No data collected**: Verify that the PingDirectory File-Based Access Logger is enabled and generating log entries, or that the Syslog Text Access Log Publisher is enabled and pointed at the correct Elastic Agent host and port. Confirm that the configured log file path or UDP listener matches the location of the Access logs. + +For help with Elastic ingest tools, check [Common problems](https://www.elastic.co/docs/troubleshoot/ingest/fleet/common-problems). + +## Reference + +### LDAP Access + +The `ldap_access` data stream provides LDAP access logs from ping_directory. + +#### LDAP Access fields + +**Exported fields** + +| Field | Description | Type | +|---|---|---| +| @timestamp | Date and time when the event occurred. | date | +| data_stream.dataset | Dataset name associated with the data stream. | constant_keyword | +| data_stream.namespace | Namespace used to group related data streams. | constant_keyword | +| data_stream.type | Type of data stream, such as logs or metrics. | constant_keyword | +| event.dataset | Identifies the PingDirectory LDAP access log dataset. | constant_keyword | +| event.module | Module that generated the event. | constant_keyword | +| input.type | Type of filebeat input. | keyword | +| log.file.device_id | ID of the device containing the filesystem where the file resides. | keyword | +| log.file.fingerprint | The sha256 fingerprint identity of the file when fingerprinting is enabled. | keyword | +| log.file.idxhi | The high-order part of a unique identifier that is associated with a file. (Windows-only). | keyword | +| log.file.idxlo | The low-order part of a unique identifier that is associated with a file. (Windows-only). | keyword | +| log.file.inode | Inode number of the log file. | keyword | +| log.file.vol | The serial number of the volume that contains a file. (Windows-only). | keyword | +| log.offset | Log offset. | long | +| log.source.address | Source address from which the log event was read / sent from. | keyword | +| observer.product | The product name of the observer that generated the event. | constant_keyword | +| observer.vendor | The vendor name of the observer that generated the event. | constant_keyword | +| ping_directory.ldap_access.additional_info | Additional diagnostic information returned with the extended operation result. | keyword | +| ping_directory.ldap_access.attrs | Requested attributes in the search. Empty means all user attributes returned. | text | +| ping_directory.ldap_access.auth_dn | Fully-resolved DN of the authenticated user after bind. May differ from bind dn. | keyword | +| ping_directory.ldap_access.auth_failure_id | Identifier associated with the authentication failure. | keyword | +| ping_directory.ldap_access.auth_failure_name | Human-readable name of the authentication failure condition. | keyword | +| ping_directory.ldap_access.auth_type | Authentication mechanism used in the Bind request. | keyword | +| ping_directory.ldap_access.base | Base DN of the LDAP search operation. | keyword | +| ping_directory.ldap_access.client_connection_policy | Name of the client connection policy applied to this connection. | keyword | +| ping_directory.ldap_access.client_ip | Client IP value recorded by PingDirectory for the operation. | ip | +| ping_directory.ldap_access.client_server_handshake_time_millis | Total time in ms for the full client-server TLS handshake. | float | +| ping_directory.ldap_access.code_location | Internal code location where the operation or event originated. | keyword | +| ping_directory.ldap_access.conn | LDAP connection ID. Each TCP connection from a client gets a unique conn value. | long | +| ping_directory.ldap_access.dn | DN of the entry that was added or modified in the directory. | keyword | +| ping_directory.ldap_access.entries_returned | Number of LDAP entries returned in the search result. | long | +| ping_directory.ldap_access.filter | LDAP search filter expression used in the search request. | keyword | +| ping_directory.ldap_access.matched_dn | DN that matched the LDAP request during processing. | keyword | +| ping_directory.ldap_access.message | Message text from a DISCONNECT operation. | text | +| ping_directory.ldap_access.msg_id | LDAP message ID from the protocol request. Used to correlate request/response. | keyword | +| ping_directory.ldap_access.op | Operation number within the connection. Increments per operation on the same conn. | long | +| ping_directory.ldap_access.op_purpose | Application name, version, and code location that triggered the modify. | keyword | +| ping_directory.ldap_access.origin | Origin from which the request was initiated. | keyword | +| ping_directory.ldap_access.pre_auth_zused_privileges | Privileges used before authorization checks, such as admin session privileges. | keyword | +| ping_directory.ldap_access.product | Product name associated with the operation or certificate information. | keyword | +| ping_directory.ldap_access.qtime | Time in milliseconds the operation waited in the queue before being processed. | float | +| ping_directory.ldap_access.request_controls | OIDs of LDAP controls attached to the modify request. | keyword | +| ping_directory.ldap_access.request_id | Unique identifier assigned to the request. | keyword | +| ping_directory.ldap_access.request_oid | OID identifying the specific LDAP extended operation requested. | keyword | +| ping_directory.ldap_access.request_type | Human-readable name of the extended operation type derived from the OID. | keyword | +| ping_directory.ldap_access.requester_dn | Distinguished Name of the authenticated user making the request. | keyword | +| ping_directory.ldap_access.requester_ip_string | Raw value of the client identifier when it is not a valid IP address (e.g. "internal"). | keyword | +| ping_directory.ldap_access.result_code | LDAP result code numeric value. 0=Success. See RFC 4511 for full list. | long | +| ping_directory.ldap_access.result_code_name | Human-readable name of the LDAP result code (e.g., Success, NoSuchObject). | keyword | +| ping_directory.ldap_access.sasl_mechanism | SASL authentication mechanism used for the bind operation. | keyword | +| ping_directory.ldap_access.scope | LDAP search scope: 0=baseObject, 1=singleLevel, 2=wholeSubtree. | byte | +| ping_directory.ldap_access.server_only_handshake_time_millis | Time in ms for the server-only portion of the TLS handshake. | float | +| ping_directory.ldap_access.session_id | Identifier associated with the client session. | keyword | +| ping_directory.ldap_access.startup_id | Identifier associated with the server startup instance. | keyword | +| ping_directory.ldap_access.streamed_entries_from_index | Number of entries streamed directly from an index during search processing. | keyword | +| ping_directory.ldap_access.thread_id | ID of the server thread that handled the LDAP operation. | keyword | +| ping_directory.ldap_access.use_dedicated_thread_pool | Indicates whether a dedicated thread pool was used to process the operation. | boolean | +| ping_directory.ldap_access.used_privileges | Server privileges used to process the operation (e.g., bypass-acl, config-read). | keyword | +| ping_directory.ldap_access.using_admin_session_worker_thread | Whether the operation used a dedicated admin session worker thread. | boolean | +| ping_directory.ldap_access.version | LDAP protocol version used in the Bind request (always 3 for LDAPv3). | keyword | +| ping_directory.ldap_access.via_detail.app | Application name extracted from the via field. | keyword | +| ping_directory.ldap_access.via_detail.client_ip | Client IP extracted from the via field. | ip | +| ping_directory.ldap_access.via_detail.request_id | Request ID extracted from the via field. | keyword | +| ping_directory.ldap_access.via_detail.session_id | Session ID extracted from the via field. | keyword | + + +### Example event + +#### LDAP Access + +An example event for `ldap_access` looks as following: + +```json +{ + "@timestamp": "2026-05-25T18:30:48.688+05:30", + "agent": { + "ephemeral_id": "21e8bfb6-0fc0-4cae-85cb-927ca9209d57", + "id": "b55cf73b-98dc-476e-b895-6d7d0fee76e6", + "name": "elastic-agent-26139", + "type": "filebeat", + "version": "8.18.0" + }, + "data_stream": { + "dataset": "ping_directory.ldap_access", + "namespace": "66896", + "type": "logs" + }, + "ecs": { + "version": "9.4.0" + }, + "elastic_agent": { + "id": "b55cf73b-98dc-476e-b895-6d7d0fee76e6", + "snapshot": false, + "version": "8.18.0" + }, + "event": { + "action": "add result", + "agent_id_status": "verified", + "category": [ + "iam" + ], + "dataset": "ping_directory.ldap_access", + "duration": 24.567, + "ingested": "2026-07-03T07:12:26Z", + "kind": "event", + "original": "[25/May/2026:18:30:48.688 +0530] ADD RESULT instanceName=\"pingdirectory-elastic-test\" threadID=9 conn=4 op=1 msgID=2 requesterIP=\"127.0.0.1\" requesterDN=\"cn=Directory Manager,cn=Root DNs,cn=config\" dn=\"ou=People,dc=example,dc=com\" resultCode=0 resultCodeName=\"Success\" qtime=0 etime=24.567 usedPrivileges=\"bypass-acl\"", + "outcome": "success", + "timezone": "+0530", + "type": [ + "change" + ] + }, + "input": { + "type": "filestream" + }, + "log": { + "file": { + "device_id": "64768", + "inode": "2492551", + "path": "/tmp/service_logs/test-ldap_access.log" + }, + "offset": 0 + }, + "observer": { + "name": "pingdirectory-elastic-test" + }, + "ping_directory": { + "ldap_access": { + "conn": 4, + "dn": "ou=People,dc=example,dc=com", + "msg_id": "2", + "op": 1, + "qtime": 0, + "requester_dn": "cn=Directory Manager,cn=Root DNs,cn=config", + "result_code": 0, + "result_code_name": "Success", + "thread_id": "9", + "used_privileges": "bypass-acl" + } + }, + "related": { + "ip": [ + "127.0.0.1" + ], + "user": [ + "ou=People,dc=example,dc=com", + "cn=Directory Manager,cn=Root DNs,cn=config" + ] + }, + "source": { + "ip": "127.0.0.1" + }, + "tags": [ + "preserve_original_event", + "forwarded", + "ping_directory-audit" + ] +} +``` + +### Inputs used + +These inputs can be used with this integration: +
+filestream + +## Setup + +For more details about the Filestream input settings, check the [Filebeat documentation](https://www.elastic.co/docs/reference/beats/filebeat/filebeat-input-filestream). + + +### Collecting logs from Filestream + +To collect logs via Filestream, select **Collect logs via Filestream** and configure the following parameters: + +- Filestream paths: The full path to the related log file. +
+
+udp + +## Setup + +For more details about the UDP input settings, check the [Filebeat documentation](https://www.elastic.co/docs/reference/beats/filebeat/filebeat-input-udp). + +### Collecting logs from UDP + +To collect logs via UDP, select **Collect logs via UDP** and configure the following parameters: + +**Required Settings:** +- Host +- Port + +**Common Optional Settings:** +- Max Message Size - Maximum size of UDP packets to accept (default: 10KB, max: 64KB) +- Read Buffer - UDP socket read buffer size for handling bursts of messages +- Read Timeout - How long to wait for incoming packets before checking for shutdown +
diff --git a/packages/ping_directory/img/ping_directory-ldap_access-dashboard.png b/packages/ping_directory/img/ping_directory-ldap_access-dashboard.png new file mode 100644 index 00000000000..102f34c7edf Binary files /dev/null and b/packages/ping_directory/img/ping_directory-ldap_access-dashboard.png differ diff --git a/packages/ping_directory/img/ping_directory-logo.svg b/packages/ping_directory/img/ping_directory-logo.svg new file mode 100644 index 00000000000..7c894bfcded --- /dev/null +++ b/packages/ping_directory/img/ping_directory-logo.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/packages/ping_directory/kibana/dashboard/ping_directory-35e0d479-ad96-46d3-b2c7-c34debf03606.json b/packages/ping_directory/kibana/dashboard/ping_directory-35e0d479-ad96-46d3-b2c7-c34debf03606.json new file mode 100644 index 00000000000..36cdbb60de5 --- /dev/null +++ b/packages/ping_directory/kibana/dashboard/ping_directory-35e0d479-ad96-46d3-b2c7-c34debf03606.json @@ -0,0 +1,525 @@ +{ + "attributes": { + "controlGroupInput": { + "chainingSystem": "HIERARCHICAL", + "controlStyle": "oneLine", + "ignoreParentSettingsJSON": { + "ignoreFilters": false, + "ignoreQuery": false, + "ignoreTimerange": false, + "ignoreValidations": false + }, + "panelsJSON": { + "f8a786f8-00dc-40f3-aa08-07b7b154c301": { + "explicitInput": { + "dataViewId": "logs-*", + "fieldName": "event.action", + "searchTechnique": "prefix", + "selectedOptions": [], + "sort": { + "by": "_count", + "direction": "desc" + } + }, + "grow": true, + "order": 0, + "type": "optionsListControl", + "width": "medium" + } + }, + "showApplySelections": false + }, + "description": "", + "kibanaSavedObjectMeta": { + "searchSourceJSON": { + "filter": [], + "query": { + "language": "kuery", + "query": "data_stream.dataset : \"ping_directory.ldap_access\" " + } + } + }, + "optionsJSON": { + "hidePanelTitles": false, + "syncColors": false, + "syncCursor": true, + "syncTooltips": false, + "useMargins": true + }, + "panelsJSON": [ + { + "embeddableConfig": { + "enhancements": { + "dynamicActions": { + "events": [] + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "logs-*", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "ping_directory.ldap_access" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "ping_directory.ldap_access" + } + } + } + ], + "query": { + "language": "kuery", + "query": "" + }, + "syncColors": false, + "syncCursor": true, + "syncTooltips": false + }, + "gridData": { + "h": 13, + "i": "477e8714-f5f2-4757-b38d-a9ef93e7edb3", + "w": 16, + "x": 32, + "y": 0 + }, + "panelIndex": "477e8714-f5f2-4757-b38d-a9ef93e7edb3", + "panelRefName": "panel_477e8714-f5f2-4757-b38d-a9ef93e7edb3", + "title": "Distribution of LDAP Operation by Types", + "type": "lens" + }, + { + "embeddableConfig": { + "enhancements": { + "dynamicActions": { + "events": [] + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "logs-*", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "ping_directory.ldap_access" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "ping_directory.ldap_access" + } + } + } + ], + "query": { + "language": "kuery", + "query": "" + }, + "syncColors": false, + "syncCursor": true, + "syncTooltips": false + }, + "gridData": { + "h": 11, + "i": "5b30887f-dd7f-4450-8943-a0763e48d0d8", + "w": 22, + "x": 26, + "y": 13 + }, + "panelIndex": "5b30887f-dd7f-4450-8943-a0763e48d0d8", + "panelRefName": "panel_5b30887f-dd7f-4450-8943-a0763e48d0d8", + "type": "lens" + }, + { + "embeddableConfig": { + "enhancements": { + "dynamicActions": { + "events": [] + } + }, + "savedVis": { + "data": { + "aggs": [], + "searchSource": { + "filter": [], + "query": { + "language": "kuery", + "query": "" + } + } + }, + "description": "", + "id": "", + "params": { + "fontSize": 12, + "markdown": "#### Overview\n\nThis dashboard provides visibility into LDAP access activity collected from PingDirectory.\n\nIt highlights LDAP operation trends, operation type distribution, and client activity across the environment, helping administrators monitor access patterns and troubleshoot bind and connection failures.\n\nVisualizations include LDAP operations over time, operation type and outcome distribution, most active clients, top search filters, and a failure breakdown table. Interactive filters on dataset and transform-source labels allow scoping the view to relevant LDAP access records for focused troubleshooting.\n\nLDAP Operations Over Time tracks operation volume per minute, helping identify usage spikes or periods of inactivity. Distribution of LDAP Operation Types breaks down events by operation (bind, search, connect, disconnect). LDAP Operation Outcome shows the split of successful vs failed operations. Most Active Clients surfaces the top source IPs generating traffic. Top Search Filters highlights the most common LDAP query patterns. Failure Breakdown lists the most common failure reasons with their operation type and occurrence count.\n\n[Integration Page](/app/integrations/detail/ping_directory/overview)\n", + "openLinksInNewTab": false + }, + "title": "", + "type": "markdown", + "uiState": {} + } + }, + "gridData": { + "h": 34, + "i": "ac324681-9cfe-43bb-a9bb-cd1617c36ff0", + "w": 12, + "x": 0, + "y": 0 + }, + "panelIndex": "ac324681-9cfe-43bb-a9bb-cd1617c36ff0", + "type": "visualization" + }, + { + "embeddableConfig": { + "enhancements": { + "dynamicActions": { + "events": [] + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "logs-*", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "ping_directory.ldap_access" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "ping_directory.ldap_access" + } + } + } + ], + "query": { + "language": "kuery", + "query": "" + }, + "syncColors": false, + "syncCursor": true, + "syncTooltips": false + }, + "gridData": { + "h": 13, + "i": "779a5b8d-24f6-41cb-a191-8cc43d37f600", + "w": 20, + "x": 12, + "y": 0 + }, + "panelIndex": "779a5b8d-24f6-41cb-a191-8cc43d37f600", + "panelRefName": "panel_779a5b8d-24f6-41cb-a191-8cc43d37f600", + "type": "lens" + }, + { + "embeddableConfig": { + "enhancements": { + "dynamicActions": { + "events": [] + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "logs-*", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "ping_directory.ldap_access" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "ping_directory.ldap_access" + } + } + } + ], + "query": { + "language": "kuery", + "query": "" + }, + "syncColors": false, + "syncCursor": true, + "syncTooltips": false + }, + "gridData": { + "h": 11, + "i": "5f8ae5f4-9845-425d-a7eb-ab5d352284f1", + "w": 14, + "x": 12, + "y": 13 + }, + "panelIndex": "5f8ae5f4-9845-425d-a7eb-ab5d352284f1", + "panelRefName": "panel_5f8ae5f4-9845-425d-a7eb-ab5d352284f1", + "type": "lens" + }, + { + "embeddableConfig": { + "description": "", + "enhancements": { + "dynamicActions": { + "events": [] + } + } + }, + "gridData": { + "h": 16, + "i": "17ec0318-d33d-4227-9ae1-6789a0537ed0", + "w": 48, + "x": 0, + "y": 34 + }, + "panelIndex": "17ec0318-d33d-4227-9ae1-6789a0537ed0", + "panelRefName": "panel_17ec0318-d33d-4227-9ae1-6789a0537ed0", + "title": "LDAP Access Essential Details", + "type": "search" + }, + { + "embeddableConfig": { + "enhancements": { + "dynamicActions": { + "events": [] + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "logs-*", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "ping_directory.ldap_access" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "ping_directory.ldap_access" + } + } + } + ], + "query": { + "language": "kuery", + "query": "" + }, + "syncColors": false, + "syncCursor": true, + "syncTooltips": false + }, + "gridData": { + "h": 10, + "i": "e070c8a3-4e27-4d93-85a1-80766145a540", + "w": 22, + "x": 12, + "y": 24 + }, + "panelIndex": "e070c8a3-4e27-4d93-85a1-80766145a540", + "panelRefName": "panel_e070c8a3-4e27-4d93-85a1-80766145a540", + "type": "lens" + }, + { + "embeddableConfig": { + "enhancements": { + "dynamicActions": { + "events": [] + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "logs-*", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "ping_directory.ldap_access" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "ping_directory.ldap_access" + } + } + } + ], + "query": { + "language": "kuery", + "query": "" + }, + "syncColors": false, + "syncCursor": true, + "syncTooltips": false + }, + "gridData": { + "h": 10, + "i": "4b1e1680-ee2c-48a2-a07c-a7318c13d5cc", + "w": 14, + "x": 34, + "y": 24 + }, + "panelIndex": "4b1e1680-ee2c-48a2-a07c-a7318c13d5cc", + "panelRefName": "panel_4b1e1680-ee2c-48a2-a07c-a7318c13d5cc", + "title": "LDAP Operation by Outcome", + "type": "lens" + } + ], + "timeRestore": false, + "title": "[Logs PingDirectory] LDAP Access", + "version": 3 + }, + "coreMigrationVersion": "8.8.0", + "created_at": "2026-07-03T06:10:28.753Z", + "id": "ping_directory-35e0d479-ad96-46d3-b2c7-c34debf03606", + "references": [ + { + "id": "ping_directory-58c4fd18-7db0-46ac-99a1-e6ec52097bee", + "name": "477e8714-f5f2-4757-b38d-a9ef93e7edb3:panel_477e8714-f5f2-4757-b38d-a9ef93e7edb3", + "type": "lens" + }, + { + "id": "ping_directory-f4653196-2b40-4f70-9d5e-a18dc7960279", + "name": "5b30887f-dd7f-4450-8943-a0763e48d0d8:panel_5b30887f-dd7f-4450-8943-a0763e48d0d8", + "type": "lens" + }, + { + "id": "ping_directory-fede7c68-f8bc-4c5d-ac15-7c6403c2206f", + "name": "779a5b8d-24f6-41cb-a191-8cc43d37f600:panel_779a5b8d-24f6-41cb-a191-8cc43d37f600", + "type": "lens" + }, + { + "id": "ping_directory-ef704c19-ed51-43c5-9687-6df7672fbc11", + "name": "5f8ae5f4-9845-425d-a7eb-ab5d352284f1:panel_5f8ae5f4-9845-425d-a7eb-ab5d352284f1", + "type": "lens" + }, + { + "id": "ping_directory-01041f5b-637d-40c3-9b6a-43c8d77e3113", + "name": "17ec0318-d33d-4227-9ae1-6789a0537ed0:panel_17ec0318-d33d-4227-9ae1-6789a0537ed0", + "type": "search" + }, + { + "id": "ping_directory-e488f69b-03ea-4f91-b824-2b0cdc1bbd61", + "name": "e070c8a3-4e27-4d93-85a1-80766145a540:panel_e070c8a3-4e27-4d93-85a1-80766145a540", + "type": "lens" + }, + { + "id": "ping_directory-015a7f2d-9876-45c1-bf85-966be64334ca", + "name": "4b1e1680-ee2c-48a2-a07c-a7318c13d5cc:panel_4b1e1680-ee2c-48a2-a07c-a7318c13d5cc", + "type": "lens" + }, + { + "id": "logs-*", + "name": "477e8714-f5f2-4757-b38d-a9ef93e7edb3:indexpattern-datasource-layer-bbd9b1c4-1c7b-43a0-b4bf-8b7d2b406a87", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "477e8714-f5f2-4757-b38d-a9ef93e7edb3:046b60e5-b422-4e2f-966b-44e338a8c764", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "5b30887f-dd7f-4450-8943-a0763e48d0d8:indexpattern-datasource-layer-4905b0c5-9b23-41ee-8cb1-03408442617a", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "5b30887f-dd7f-4450-8943-a0763e48d0d8:d1b96d55-110f-49a3-b790-322c7c642839", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "779a5b8d-24f6-41cb-a191-8cc43d37f600:indexpattern-datasource-layer-aa31e0d4-d8e8-4dee-be81-13202fca6168", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "779a5b8d-24f6-41cb-a191-8cc43d37f600:f8bb8b6e-dc77-4688-8a40-07ce66d8148a", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "5f8ae5f4-9845-425d-a7eb-ab5d352284f1:indexpattern-datasource-layer-d8940a8d-acd4-4086-961f-6eb0f0fd1926", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "5f8ae5f4-9845-425d-a7eb-ab5d352284f1:5352afbd-3201-4e07-9712-13207140c7f0", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "e070c8a3-4e27-4d93-85a1-80766145a540:indexpattern-datasource-layer-de101397-45e8-4f4b-b861-675aa96f9341", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "e070c8a3-4e27-4d93-85a1-80766145a540:34538fa0-c6b7-4ae1-ba01-8c74a3d76cd4", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "4b1e1680-ee2c-48a2-a07c-a7318c13d5cc:indexpattern-datasource-layer-8a9d4202-58a9-440a-a078-d6806d7a6136", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "4b1e1680-ee2c-48a2-a07c-a7318c13d5cc:a3eccf0b-b41c-471c-a31d-1681dceb873a", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "controlGroup_f8a786f8-00dc-40f3-aa08-07b7b154c301:optionsListDataView", + "type": "index-pattern" + } + ], + "type": "dashboard", + "typeMigrationVersion": "10.2.0" +} \ No newline at end of file diff --git a/packages/ping_directory/kibana/lens/ping_directory-015a7f2d-9876-45c1-bf85-966be64334ca.json b/packages/ping_directory/kibana/lens/ping_directory-015a7f2d-9876-45c1-bf85-966be64334ca.json new file mode 100644 index 00000000000..d9a3f34af99 --- /dev/null +++ b/packages/ping_directory/kibana/lens/ping_directory-015a7f2d-9876-45c1-bf85-966be64334ca.json @@ -0,0 +1,155 @@ +{ + "attributes": { + "description": "", + "state": { + "adHocDataViews": {}, + "datasourceStates": { + "formBased": { + "layers": { + "8a9d4202-58a9-440a-a078-d6806d7a6136": { + "columnOrder": [ + "d8bf1f7f-e767-4687-a30f-8c6604b8cd76", + "e30d32ad-a759-4dd8-8068-f88780f10722" + ], + "columns": { + "d8bf1f7f-e767-4687-a30f-8c6604b8cd76": { + "dataType": "string", + "isBucketed": true, + "label": "Top 5 values of event.outcome", + "operationType": "terms", + "params": { + "exclude": [], + "excludeIsRegex": false, + "include": [], + "includeIsRegex": false, + "missingBucket": false, + "orderBy": { + "columnId": "e30d32ad-a759-4dd8-8068-f88780f10722", + "type": "column" + }, + "orderDirection": "desc", + "otherBucket": true, + "parentFormat": { + "id": "terms" + }, + "size": 5 + }, + "scale": "ordinal", + "sourceField": "event.outcome" + }, + "e30d32ad-a759-4dd8-8068-f88780f10722": { + "customLabel": true, + "dataType": "number", + "isBucketed": false, + "label": "Count ", + "operationType": "count", + "params": { + "emptyAsNull": false + }, + "scale": "ratio", + "sourceField": "___records___" + } + }, + "ignoreGlobalFilters": false, + "incompleteColumns": {}, + "sampling": 1 + } + } + }, + "indexpattern": { + "layers": {} + }, + "textBased": { + "layers": {} + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "a3eccf0b-b41c-471c-a31d-1681dceb873a", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "ping_directory.ldap_access" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "ping_directory.ldap_access" + } + } + } + ], + "internalReferences": [], + "query": { + "language": "kuery", + "query": "" + }, + "visualization": { + "layers": [ + { + "categoryDisplay": "default", + "colorMapping": { + "assignments": [], + "colorMode": { + "type": "categorical" + }, + "paletteId": "eui_amsterdam_color_blind", + "specialAssignments": [ + { + "color": { + "type": "loop" + }, + "rule": { + "type": "other" + }, + "touched": false + } + ] + }, + "layerId": "8a9d4202-58a9-440a-a078-d6806d7a6136", + "layerType": "data", + "legendDisplay": "show", + "metrics": [ + "e30d32ad-a759-4dd8-8068-f88780f10722" + ], + "nestedLegend": false, + "numberDisplay": "percent", + "primaryGroups": [ + "d8bf1f7f-e767-4687-a30f-8c6604b8cd76" + ], + "truncateLegend": false + } + ], + "shape": "pie" + } + }, + "title": "LDAP Operation by Outcome", + "visualizationType": "lnsPie" + }, + "coreMigrationVersion": "8.8.0", + "created_at": "2026-07-03T06:13:15.829Z", + "created_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0", + "id": "ping_directory-015a7f2d-9876-45c1-bf85-966be64334ca", + "references": [ + { + "id": "logs-*", + "name": "indexpattern-datasource-layer-8a9d4202-58a9-440a-a078-d6806d7a6136", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "a3eccf0b-b41c-471c-a31d-1681dceb873a", + "type": "index-pattern" + } + ], + "type": "lens", + "typeMigrationVersion": "8.9.0" +} \ No newline at end of file diff --git a/packages/ping_directory/kibana/lens/ping_directory-58c4fd18-7db0-46ac-99a1-e6ec52097bee.json b/packages/ping_directory/kibana/lens/ping_directory-58c4fd18-7db0-46ac-99a1-e6ec52097bee.json new file mode 100644 index 00000000000..b695deaa379 --- /dev/null +++ b/packages/ping_directory/kibana/lens/ping_directory-58c4fd18-7db0-46ac-99a1-e6ec52097bee.json @@ -0,0 +1,155 @@ +{ + "attributes": { + "description": "", + "state": { + "adHocDataViews": {}, + "datasourceStates": { + "formBased": { + "layers": { + "bbd9b1c4-1c7b-43a0-b4bf-8b7d2b406a87": { + "columnOrder": [ + "91435dc8-58d5-400a-8a0a-652f336450dd", + "74b5f303-f51c-4c51-a0e0-f25cd4052b3f" + ], + "columns": { + "74b5f303-f51c-4c51-a0e0-f25cd4052b3f": { + "customLabel": true, + "dataType": "number", + "isBucketed": false, + "label": "Count ", + "operationType": "count", + "params": { + "emptyAsNull": false + }, + "scale": "ratio", + "sourceField": "___records___" + }, + "91435dc8-58d5-400a-8a0a-652f336450dd": { + "dataType": "string", + "isBucketed": true, + "label": "Top 5 values of event.action", + "operationType": "terms", + "params": { + "exclude": [], + "excludeIsRegex": false, + "include": [], + "includeIsRegex": false, + "missingBucket": false, + "orderBy": { + "columnId": "74b5f303-f51c-4c51-a0e0-f25cd4052b3f", + "type": "column" + }, + "orderDirection": "desc", + "otherBucket": true, + "parentFormat": { + "id": "terms" + }, + "size": 5 + }, + "scale": "ordinal", + "sourceField": "event.action" + } + }, + "ignoreGlobalFilters": false, + "incompleteColumns": {}, + "sampling": 1 + } + } + }, + "indexpattern": { + "layers": {} + }, + "textBased": { + "layers": {} + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "046b60e5-b422-4e2f-966b-44e338a8c764", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "ping_directory.ldap_access" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "ping_directory.ldap_access" + } + } + } + ], + "internalReferences": [], + "query": { + "language": "kuery", + "query": "" + }, + "visualization": { + "layers": [ + { + "categoryDisplay": "default", + "colorMapping": { + "assignments": [], + "colorMode": { + "type": "categorical" + }, + "paletteId": "eui_amsterdam_color_blind", + "specialAssignments": [ + { + "color": { + "type": "loop" + }, + "rule": { + "type": "other" + }, + "touched": false + } + ] + }, + "layerId": "bbd9b1c4-1c7b-43a0-b4bf-8b7d2b406a87", + "layerType": "data", + "legendDisplay": "show", + "metrics": [ + "74b5f303-f51c-4c51-a0e0-f25cd4052b3f" + ], + "nestedLegend": false, + "numberDisplay": "percent", + "primaryGroups": [ + "91435dc8-58d5-400a-8a0a-652f336450dd" + ], + "truncateLegend": false + } + ], + "shape": "pie" + } + }, + "title": "Distribution of LDAP Operation by Types", + "visualizationType": "lnsPie" + }, + "coreMigrationVersion": "8.8.0", + "created_at": "2026-07-03T06:12:21.570Z", + "created_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0", + "id": "ping_directory-58c4fd18-7db0-46ac-99a1-e6ec52097bee", + "references": [ + { + "id": "logs-*", + "name": "indexpattern-datasource-layer-bbd9b1c4-1c7b-43a0-b4bf-8b7d2b406a87", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "046b60e5-b422-4e2f-966b-44e338a8c764", + "type": "index-pattern" + } + ], + "type": "lens", + "typeMigrationVersion": "8.9.0" +} \ No newline at end of file diff --git a/packages/ping_directory/kibana/lens/ping_directory-e488f69b-03ea-4f91-b824-2b0cdc1bbd61.json b/packages/ping_directory/kibana/lens/ping_directory-e488f69b-03ea-4f91-b824-2b0cdc1bbd61.json new file mode 100644 index 00000000000..20cc387bdd5 --- /dev/null +++ b/packages/ping_directory/kibana/lens/ping_directory-e488f69b-03ea-4f91-b824-2b0cdc1bbd61.json @@ -0,0 +1,158 @@ +{ + "attributes": { + "description": "", + "state": { + "adHocDataViews": {}, + "datasourceStates": { + "formBased": { + "layers": { + "de101397-45e8-4f4b-b861-675aa96f9341": { + "columnOrder": [ + "42b2f4a3-8daf-4994-aaf5-8a8ed3a91b15", + "980f074d-207c-4c5a-ac73-0e6d998cddc2" + ], + "columns": { + "42b2f4a3-8daf-4994-aaf5-8a8ed3a91b15": { + "customLabel": true, + "dataType": "string", + "isBucketed": true, + "label": "Search Filter", + "operationType": "terms", + "params": { + "exclude": [], + "excludeIsRegex": false, + "include": [], + "includeIsRegex": false, + "missingBucket": false, + "orderBy": { + "columnId": "980f074d-207c-4c5a-ac73-0e6d998cddc2", + "type": "column" + }, + "orderDirection": "desc", + "otherBucket": true, + "parentFormat": { + "id": "terms" + }, + "size": 10 + }, + "scale": "ordinal", + "sourceField": "ping_directory.ldap_access.filter" + }, + "980f074d-207c-4c5a-ac73-0e6d998cddc2": { + "customLabel": true, + "dataType": "number", + "isBucketed": false, + "label": "Count ", + "operationType": "count", + "params": { + "emptyAsNull": false + }, + "scale": "ratio", + "sourceField": "___records___" + } + }, + "ignoreGlobalFilters": false, + "incompleteColumns": {}, + "sampling": 1 + } + } + }, + "indexpattern": { + "layers": {} + }, + "textBased": { + "layers": {} + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "34538fa0-c6b7-4ae1-ba01-8c74a3d76cd4", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "ping_directory.ldap_access" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "ping_directory.ldap_access" + } + } + } + ], + "internalReferences": [], + "query": { + "language": "kuery", + "query": "" + }, + "visualization": { + "layers": [ + { + "accessors": [ + "980f074d-207c-4c5a-ac73-0e6d998cddc2" + ], + "colorMapping": { + "assignments": [], + "colorMode": { + "type": "categorical" + }, + "paletteId": "eui_amsterdam_color_blind", + "specialAssignments": [ + { + "color": { + "type": "loop" + }, + "rule": { + "type": "other" + }, + "touched": false + } + ] + }, + "layerId": "de101397-45e8-4f4b-b861-675aa96f9341", + "layerType": "data", + "position": "top", + "seriesType": "bar_stacked", + "showGridlines": false, + "xAccessor": "42b2f4a3-8daf-4994-aaf5-8a8ed3a91b15" + } + ], + "legend": { + "isVisible": true, + "position": "right" + }, + "preferredSeriesType": "bar_stacked", + "title": "Empty XY chart", + "valueLabels": "hide" + } + }, + "title": "Top Search Filters", + "visualizationType": "lnsXY" + }, + "coreMigrationVersion": "8.8.0", + "created_at": "2026-07-02T09:54:02.286Z", + "created_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0", + "id": "ping_directory-e488f69b-03ea-4f91-b824-2b0cdc1bbd61", + "references": [ + { + "id": "logs-*", + "name": "indexpattern-datasource-layer-de101397-45e8-4f4b-b861-675aa96f9341", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "34538fa0-c6b7-4ae1-ba01-8c74a3d76cd4", + "type": "index-pattern" + } + ], + "type": "lens", + "typeMigrationVersion": "8.9.0" +} \ No newline at end of file diff --git a/packages/ping_directory/kibana/lens/ping_directory-ef704c19-ed51-43c5-9687-6df7672fbc11.json b/packages/ping_directory/kibana/lens/ping_directory-ef704c19-ed51-43c5-9687-6df7672fbc11.json new file mode 100644 index 00000000000..0b4a901b070 --- /dev/null +++ b/packages/ping_directory/kibana/lens/ping_directory-ef704c19-ed51-43c5-9687-6df7672fbc11.json @@ -0,0 +1,158 @@ +{ + "attributes": { + "description": "", + "state": { + "adHocDataViews": {}, + "datasourceStates": { + "formBased": { + "layers": { + "d8940a8d-acd4-4086-961f-6eb0f0fd1926": { + "columnOrder": [ + "297f0eb8-5149-409d-b602-0efcc991419e", + "9a9c8d55-6ad8-4d5d-86c9-101cbe19b3ce" + ], + "columns": { + "297f0eb8-5149-409d-b602-0efcc991419e": { + "customLabel": true, + "dataType": "ip", + "isBucketed": true, + "label": "Source IP", + "operationType": "terms", + "params": { + "exclude": [], + "excludeIsRegex": false, + "include": [], + "includeIsRegex": false, + "missingBucket": false, + "orderBy": { + "columnId": "9a9c8d55-6ad8-4d5d-86c9-101cbe19b3ce", + "type": "column" + }, + "orderDirection": "desc", + "otherBucket": true, + "parentFormat": { + "id": "terms" + }, + "size": 10 + }, + "scale": "ordinal", + "sourceField": "source.ip" + }, + "9a9c8d55-6ad8-4d5d-86c9-101cbe19b3ce": { + "customLabel": true, + "dataType": "number", + "isBucketed": false, + "label": "Count ", + "operationType": "count", + "params": { + "emptyAsNull": false + }, + "scale": "ratio", + "sourceField": "___records___" + } + }, + "ignoreGlobalFilters": false, + "incompleteColumns": {}, + "sampling": 1 + } + } + }, + "indexpattern": { + "layers": {} + }, + "textBased": { + "layers": {} + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "5352afbd-3201-4e07-9712-13207140c7f0", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "ping_directory.ldap_access" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "ping_directory.ldap_access" + } + } + } + ], + "internalReferences": [], + "query": { + "language": "kuery", + "query": "" + }, + "visualization": { + "layers": [ + { + "accessors": [ + "9a9c8d55-6ad8-4d5d-86c9-101cbe19b3ce" + ], + "colorMapping": { + "assignments": [], + "colorMode": { + "type": "categorical" + }, + "paletteId": "eui_amsterdam_color_blind", + "specialAssignments": [ + { + "color": { + "type": "loop" + }, + "rule": { + "type": "other" + }, + "touched": false + } + ] + }, + "layerId": "d8940a8d-acd4-4086-961f-6eb0f0fd1926", + "layerType": "data", + "position": "top", + "seriesType": "bar_stacked", + "showGridlines": false, + "xAccessor": "297f0eb8-5149-409d-b602-0efcc991419e" + } + ], + "legend": { + "isVisible": true, + "position": "right" + }, + "preferredSeriesType": "bar_stacked", + "title": "Empty XY chart", + "valueLabels": "hide" + } + }, + "title": "Most Active Clients", + "visualizationType": "lnsXY" + }, + "coreMigrationVersion": "8.8.0", + "created_at": "2026-07-02T09:56:42.494Z", + "created_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0", + "id": "ping_directory-ef704c19-ed51-43c5-9687-6df7672fbc11", + "references": [ + { + "id": "logs-*", + "name": "indexpattern-datasource-layer-d8940a8d-acd4-4086-961f-6eb0f0fd1926", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "5352afbd-3201-4e07-9712-13207140c7f0", + "type": "index-pattern" + } + ], + "type": "lens", + "typeMigrationVersion": "8.9.0" +} \ No newline at end of file diff --git a/packages/ping_directory/kibana/lens/ping_directory-f4653196-2b40-4f70-9d5e-a18dc7960279.json b/packages/ping_directory/kibana/lens/ping_directory-f4653196-2b40-4f70-9d5e-a18dc7960279.json new file mode 100644 index 00000000000..e02db74bfd6 --- /dev/null +++ b/packages/ping_directory/kibana/lens/ping_directory-f4653196-2b40-4f70-9d5e-a18dc7960279.json @@ -0,0 +1,166 @@ +{ + "attributes": { + "description": "", + "state": { + "adHocDataViews": {}, + "datasourceStates": { + "formBased": { + "layers": { + "4905b0c5-9b23-41ee-8cb1-03408442617a": { + "columnOrder": [ + "d272b6c2-8bef-43e7-937b-7d73fcccd602", + "1665fd82-891e-43a1-8a01-a33a789e50c1", + "a21d79cc-092f-41ed-9933-55716b9ad1ed" + ], + "columns": { + "1665fd82-891e-43a1-8a01-a33a789e50c1": { + "customLabel": true, + "dataType": "string", + "isBucketed": true, + "label": "Action", + "operationType": "terms", + "params": { + "exclude": [], + "excludeIsRegex": false, + "include": [], + "includeIsRegex": false, + "missingBucket": false, + "orderBy": { + "columnId": "a21d79cc-092f-41ed-9933-55716b9ad1ed", + "type": "column" + }, + "orderDirection": "desc", + "otherBucket": false, + "parentFormat": { + "id": "terms" + }, + "size": 10 + }, + "scale": "ordinal", + "sourceField": "event.action" + }, + "a21d79cc-092f-41ed-9933-55716b9ad1ed": { + "customLabel": true, + "dataType": "number", + "isBucketed": false, + "label": "Count ", + "operationType": "count", + "params": { + "emptyAsNull": false + }, + "scale": "ratio", + "sourceField": "___records___" + }, + "d272b6c2-8bef-43e7-937b-7d73fcccd602": { + "customLabel": true, + "dataType": "string", + "isBucketed": true, + "label": "Reason for Failure", + "operationType": "terms", + "params": { + "exclude": [], + "excludeIsRegex": false, + "include": [], + "includeIsRegex": false, + "missingBucket": false, + "orderBy": { + "columnId": "a21d79cc-092f-41ed-9933-55716b9ad1ed", + "type": "column" + }, + "orderDirection": "desc", + "otherBucket": false, + "parentFormat": { + "id": "terms" + }, + "size": 10 + }, + "scale": "ordinal", + "sourceField": "event.reason" + } + }, + "ignoreGlobalFilters": false, + "incompleteColumns": {}, + "sampling": 1 + } + } + }, + "indexpattern": { + "layers": {} + }, + "textBased": { + "layers": {} + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "d1b96d55-110f-49a3-b790-322c7c642839", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "ping_directory.ldap_access" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "ping_directory.ldap_access" + } + } + } + ], + "internalReferences": [], + "query": { + "language": "kuery", + "query": "" + }, + "visualization": { + "columns": [ + { + "columnId": "d272b6c2-8bef-43e7-937b-7d73fcccd602", + "isMetric": false, + "isTransposed": false + }, + { + "columnId": "1665fd82-891e-43a1-8a01-a33a789e50c1", + "isMetric": false, + "isTransposed": false + }, + { + "columnId": "a21d79cc-092f-41ed-9933-55716b9ad1ed", + "isMetric": true, + "isTransposed": false + } + ], + "layerId": "4905b0c5-9b23-41ee-8cb1-03408442617a", + "layerType": "data" + } + }, + "title": "Failure Breakdown", + "visualizationType": "lnsDatatable" + }, + "coreMigrationVersion": "8.8.0", + "created_at": "2026-07-02T09:34:57.858Z", + "created_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0", + "id": "ping_directory-f4653196-2b40-4f70-9d5e-a18dc7960279", + "references": [ + { + "id": "logs-*", + "name": "indexpattern-datasource-layer-4905b0c5-9b23-41ee-8cb1-03408442617a", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "d1b96d55-110f-49a3-b790-322c7c642839", + "type": "index-pattern" + } + ], + "type": "lens", + "typeMigrationVersion": "8.9.0" +} \ No newline at end of file diff --git a/packages/ping_directory/kibana/lens/ping_directory-fede7c68-f8bc-4c5d-ac15-7c6403c2206f.json b/packages/ping_directory/kibana/lens/ping_directory-fede7c68-f8bc-4c5d-ac15-7c6403c2206f.json new file mode 100644 index 00000000000..fc58d38282c --- /dev/null +++ b/packages/ping_directory/kibana/lens/ping_directory-fede7c68-f8bc-4c5d-ac15-7c6403c2206f.json @@ -0,0 +1,174 @@ +{ + "attributes": { + "description": "", + "state": { + "adHocDataViews": {}, + "datasourceStates": { + "formBased": { + "layers": { + "aa31e0d4-d8e8-4dee-be81-13202fca6168": { + "columnOrder": [ + "0de6803a-2f35-403e-ba7e-5abff7be15d3", + "e61df96a-5517-4193-8bba-10940c5f9849", + "9cba7aaf-5cf4-4992-b1f8-1ddba63cd208" + ], + "columns": { + "0de6803a-2f35-403e-ba7e-5abff7be15d3": { + "dataType": "string", + "isBucketed": true, + "label": "Top 5 values of event.action", + "operationType": "terms", + "params": { + "exclude": [], + "excludeIsRegex": false, + "include": [], + "includeIsRegex": false, + "missingBucket": false, + "orderBy": { + "columnId": "9cba7aaf-5cf4-4992-b1f8-1ddba63cd208", + "type": "column" + }, + "orderDirection": "desc", + "otherBucket": true, + "parentFormat": { + "id": "terms" + }, + "size": 5 + }, + "scale": "ordinal", + "sourceField": "event.action" + }, + "9cba7aaf-5cf4-4992-b1f8-1ddba63cd208": { + "customLabel": true, + "dataType": "number", + "isBucketed": false, + "label": "Count", + "operationType": "count", + "params": { + "emptyAsNull": false + }, + "scale": "ratio", + "sourceField": "___records___" + }, + "e61df96a-5517-4193-8bba-10940c5f9849": { + "dataType": "date", + "isBucketed": true, + "label": "@timestamp", + "operationType": "date_histogram", + "params": { + "dropPartials": false, + "includeEmptyRows": true, + "interval": "auto" + }, + "scale": "interval", + "sourceField": "@timestamp" + } + }, + "ignoreGlobalFilters": false, + "incompleteColumns": {}, + "sampling": 1 + } + } + }, + "indexpattern": { + "layers": {} + }, + "textBased": { + "layers": {} + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "f8bb8b6e-dc77-4688-8a40-07ce66d8148a", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "ping_directory.ldap_access" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "ping_directory.ldap_access" + } + } + } + ], + "internalReferences": [], + "query": { + "language": "kuery", + "query": "" + }, + "visualization": { + "layers": [ + { + "accessors": [ + "9cba7aaf-5cf4-4992-b1f8-1ddba63cd208" + ], + "colorMapping": { + "assignments": [], + "colorMode": { + "type": "categorical" + }, + "paletteId": "eui_amsterdam_color_blind", + "specialAssignments": [ + { + "color": { + "type": "loop" + }, + "rule": { + "type": "other" + }, + "touched": false + } + ] + }, + "layerId": "aa31e0d4-d8e8-4dee-be81-13202fca6168", + "layerType": "data", + "position": "top", + "seriesType": "line", + "showGridlines": false, + "splitAccessor": "0de6803a-2f35-403e-ba7e-5abff7be15d3", + "xAccessor": "e61df96a-5517-4193-8bba-10940c5f9849" + } + ], + "legend": { + "isVisible": true, + "position": "right", + "shouldTruncate": false, + "showSingleSeries": true + }, + "preferredSeriesType": "line", + "title": "Empty XY chart", + "valueLabels": "hide" + } + }, + "title": "LDAP Operations over Time", + "visualizationType": "lnsXY" + }, + "coreMigrationVersion": "8.8.0", + "created_at": "2026-07-02T09:06:16.465Z", + "created_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0", + "id": "ping_directory-fede7c68-f8bc-4c5d-ac15-7c6403c2206f", + "references": [ + { + "id": "logs-*", + "name": "indexpattern-datasource-layer-aa31e0d4-d8e8-4dee-be81-13202fca6168", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "f8bb8b6e-dc77-4688-8a40-07ce66d8148a", + "type": "index-pattern" + } + ], + "type": "lens", + "typeMigrationVersion": "8.9.0" +} \ No newline at end of file diff --git a/packages/ping_directory/kibana/search/ping_directory-01041f5b-637d-40c3-9b6a-43c8d77e3113.json b/packages/ping_directory/kibana/search/ping_directory-01041f5b-637d-40c3-9b6a-43c8d77e3113.json new file mode 100644 index 00000000000..8db7458b233 --- /dev/null +++ b/packages/ping_directory/kibana/search/ping_directory-01041f5b-637d-40c3-9b6a-43c8d77e3113.json @@ -0,0 +1,46 @@ +{ + "attributes": { + "columns": [ + "event.action", + "source.ip", + "event.outcome", + "event.duration", + "ping_directory.ldap_access.filter" + ], + "description": "", + "grid": {}, + "hideChart": false, + "isTextBasedQuery": false, + "kibanaSavedObjectMeta": { + "searchSourceJSON": { + "filter": [], + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.index", + "query": { + "language": "kuery", + "query": "data_stream.dataset : \"ping_directory.ldap_access\" " + } + } + }, + "sort": [ + [ + "@timestamp", + "desc" + ] + ], + "timeRestore": false, + "title": "LDAP Access Essential Details" + }, + "coreMigrationVersion": "8.8.0", + "created_at": "2026-07-02T10:11:29.567Z", + "created_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0", + "id": "ping_directory-01041f5b-637d-40c3-9b6a-43c8d77e3113", + "references": [ + { + "id": "logs-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + } + ], + "type": "search", + "typeMigrationVersion": "10.5.0" +} \ No newline at end of file diff --git a/packages/ping_directory/manifest.yml b/packages/ping_directory/manifest.yml new file mode 100644 index 00000000000..cb83d16eec6 --- /dev/null +++ b/packages/ping_directory/manifest.yml @@ -0,0 +1,41 @@ +format_version: 3.6.0 +name: ping_directory +title: PingDirectory +version: 0.1.0 +source: + license: 'Elastic-2.0' +description: 'Collect logs from PingDirectory with Elastic Agent.' +type: integration +categories: + - security + - authentication + - iam +conditions: + kibana: + version: '^8.18.0 || ^9.1.0' + elastic: + subscription: 'basic' +screenshots: + - src: /img/ping_directory-ldap_access-dashboard.png + title: LDAP Access Dashboard + size: 600x600 + type: image/png +icons: + - src: /img/ping_directory-logo.svg + title: ping_directory logo + size: 32x32 + type: image/svg+xml +policy_templates: + - name: ping_directory + title: PingDirectory logs + description: Collect PingDirectory logs via filestream. + inputs: + - type: udp + title: Collect PingDirectory logs via UDP + description: Collecting logs from PingDirectory via UDP. + - type: filestream + title: Collect PingDirectory logs via Filestream + description: Collecting logs from PingDirectory via File. +owner: + github: elastic/security-service-integrations + type: elastic diff --git a/packages/ping_directory/sample_event.json b/packages/ping_directory/sample_event.json new file mode 100644 index 00000000000..2cf93e50bd5 --- /dev/null +++ b/packages/ping_directory/sample_event.json @@ -0,0 +1,3 @@ +{ + "description": "This is an example sample-event for New Package. Replace it with a real sample event. Hint: If system tests exist, running `elastic-package test system --generate` will generate this file." +} diff --git a/packages/ping_directory/validation.yml b/packages/ping_directory/validation.yml new file mode 100644 index 00000000000..1189aa63c89 --- /dev/null +++ b/packages/ping_directory/validation.yml @@ -0,0 +1,3 @@ +errors: + exclude_checks: + - SVR00004 # References in dashboards.