File: //usr/share/filebeat/module/oracle/database_audit/ingest/pipeline.yml
description: Pipeline for parsing Oracle Audit logs
processors:
- set:
field: event.ingested
value: "{{_ingest.timestamp}}"
- set:
field: event.action
value: database_audit
- set:
field: event.kind
value: event
- set:
field: event.category
value: database
- set:
field: event.type
value: access
- set:
field: event.outcome
value: success
- grok:
field: message
patterns:
- "%{GREEDYDATA:tmp_timestamp}\\\nLENGTH : '%{GREEDYDATA:LENGTH}'\\\n(?m)%{GREEDYDATA:audit}"
- "%{GREEDYDATA:tmp_timestamp}\\\nLENGTH: \"%{GREEDYDATA:LENGTH}\"\\\n(?m)%{GREEDYDATA:auth}"
- kv:
field: audit
field_split: "\\\n(?=[a-zA-Z])"
value_split: ":\\S\\d+\\S(?= ')"
trim_value: " '"
trim_key: " "
prefix: oracle.database_audit.
if: ctx?.audit != null && ctx?.auth == null
- gsub:
field: auth
pattern: "\"\\s"
replacement: "\"\\|"
ignore_missing: true
- kv:
field: auth
field_split: "\\|"
value_split: ':\S\d+\S(?= ")'
prefix: oracle.database_audit.
trim_key: " "
trim_value: "\" "
if: ctx?.auth != null
- rename:
field: auth
target_field: audit
ignore_missing: true
- grok:
field: log.file.path
patterns:
- "%{BASE10NUM:process.pid}\\_%{BASE10NUM}\\.aud(\\.log)?$"
# All field names are uppercase by default, converts them to lowercase
- script:
source: "ctx.oracle.database_audit = ctx.oracle.database_audit.entrySet().stream().collect(Collectors.toMap(entry -> entry.getKey().toLowerCase(), Map.Entry::getValue));"
lang: painless
if: ctx.oracle?.database_audit != null
# Replace all field names that has spaces in them with _
- script:
lang: painless
source: "ctx.oracle.database_audit = ctx?.oracle?.database_audit.entrySet().stream().collect(Collectors.toMap(e -> e.getKey().replace(' ', '_'), e -> e.getValue()));"
if: ctx.oracle?.database_audit != null
- script:
lang: painless
source: "ctx.oracle.database_audit = ctx.oracle.database_audit.entrySet().stream().collect(Collectors.toMap(e -> e.getKey().replace('$', '_'), e -> e.getValue()));"
if: ctx.oracle?.database_audit != null
- grok:
field: oracle.database_audit.comment$text
patterns:
- 'Authenticated by: DATABASE; Client address: \(ADDRESS=\(PROTOCOL=%{WORD:network.transport}\)\(HOST=%{IP:source.ip}\)\(PORT=%{INT:source.port}\)\)'
ignore_missing: true
- script:
source: |-
def x = ctx.oracle.database_audit.action_number;
if (x == 100) {
ctx.oracle.database_audit.action = "LOGON";
}
if (x == 101) {
ctx.oracle.database_audit.action = "LOGOFF";
}
if (x == 102) {
ctx.oracle.database_audit.action = "LOGOFF BY CLEANUP";
}
if: "[100, 101, 102].contains(ctx.oracle?.database_audit?.action_number)"
- append:
field: event.category
value:
- authentication
if: "(ctx.oracle?.database_audit?.action == '100' && ['0', '1017'].contains(ctx.oracle?.database_audit?.returncode)) || ['101', '102'].contains(ctx.oracle?.database_audit?.action)"
- append:
field: event.action
value:
- logon-failed
if: ctx.oracle?.database_audit?.action == '100' && ctx.oracle?.database_audit?.returncode == '1017'
- append:
field: event.action
value:
- logged-in
if: ctx.oracle?.database_audit?.action == '100' && ctx.oracle?.database_audit?.returncode == '0'
- append:
field: event.action
value:
- logout
if: "['101', '102'].contains(ctx.oracle?.database_audit?.action)"
- set:
field: event.outcome
value: failure
if: ctx.oracle?.database_audit?.action == '100' && ctx.oracle?.database_audit?.returncode == '1017'
- gsub:
field: "oracle.database_audit.action"
pattern: "\\n"
replacement: ""
if: ctx.oracle?.database_audit?.action != null
- gsub:
field: "oracle.database_audit.action"
pattern: "\\s{2,}"
replacement: " "
if: ctx.oracle?.database_audit?.action != null
- trim:
field: "oracle.database_audit.action_number"
ignore_missing: true
# Removes all null values from ctx.*
- script:
lang: painless
if: ctx?.oracle?.database_audit != null
source: |
void handleMap(Map map) {
for (def x : map.values()) {
if (x instanceof Map) {
handleMap(x);
} else if (x instanceof List) {
handleList(x);
}
}
map.values().removeIf(v -> v instanceof String && v.isEmpty() == true);
}
void handleList(List list) {
for (def x : list) {
if (x instanceof Map) {
handleMap(x);
} else if (x instanceof List) {
handleList(x);
}
}
}
handleMap(ctx);
- remove:
field:
- "@timestamp"
ignore_missing: true
- date:
field: tmp_timestamp
target_field: "@timestamp"
formats:
- EEE MMM [ d][dd] HH:mm:ss uuuu XXX
- grok:
field: tmp_timestamp
patterns:
- "%{ISO8601_TIMEZONE:event.timezone}$"
- rename:
field: oracle.database_audit.privilege
target_field: user.roles
ignore_missing: true
- rename:
field: LENGTH
target_field: oracle.database_audit.length
ignore_missing: true
- rename:
field: oracle.database_audit.client_user
target_field: client.user.name
ignore_missing: true
- rename:
field: oracle.database_audit.client_address
target_field: client.address
ignore_missing: true
- rename:
field: oracle.database_audit.userhost
target_field: server.address
ignore_missing: true
- rename:
field: oracle.database_audit.database_user
target_field: server.user.name
ignore_missing: true
- convert:
field: oracle.database_audit.length
type: long
ignore_missing: true
if: ctx.oracle?.database_audit != null
- grok:
field: client.address
patterns:
- "(?:%{IP:client.ip}|%{GREEDYDATA:client.domain})"
ignore_failure: true
ignore_missing: true
- grok:
field: server.address
patterns:
- "(?:%{IP:server.ip}|%{GREEDYDATA:server.domain})"
ignore_failure: true
ignore_missing: true
# Renaming certain fields for better data structure
- rename:
field: oracle.database_audit.sessionid
target_field: oracle.database_audit.session_id
ignore_missing: true
- rename:
field: oracle.database_audit.client_terminal
target_field: oracle.database_audit.client.terminal
ignore_missing: true
- rename:
field: oracle.database_audit.client_address
target_field: oracle.database_audit.client.address
ignore_missing: true
- rename:
field: oracle.database_audit.database_user
target_field: oracle.database_audit.database.user
ignore_missing: true
- rename:
field: oracle.database_audit.userhost
target_field: oracle.database_audit.database.host
ignore_missing: true
- rename:
field: oracle.database_audit.dbid
target_field: oracle.database_audit.database.id
ignore_missing: true
- rename:
field: oracle.database_audit.entry_id
target_field: oracle.database_audit.entry.id
ignore_missing: true
- remove:
field:
- tmp_timestamp
- audit
- message
ignore_missing: true
- geoip:
field: source.ip
target_field: source.geo
ignore_missing: true
- geoip:
target_field: source.as
properties:
- asn
- organization_name
ignore_missing: true
database_file: GeoLite2-ASN.mmdb
field: source.ip
- rename:
target_field: source.as.number
ignore_missing: true
field: source.as.asn
- rename:
field: source.as.organization_name
target_field: source.as.organization.name
ignore_missing: true
- geoip:
field: client.ip
target_field: client.geo
ignore_missing: true
- geoip:
target_field: client.as
properties:
- asn
- organization_name
ignore_missing: true
database_file: GeoLite2-ASN.mmdb
field: client.ip
- rename:
target_field: client.as.number
ignore_missing: true
field: client.as.asn
- rename:
field: client.as.organization_name
target_field: client.as.organization.name
ignore_missing: true
- geoip:
field: server.ip
target_field: server.geo
ignore_missing: true
- geoip:
target_field: server.as
properties:
- asn
- organization_name
ignore_missing: true
database_file: GeoLite2-ASN.mmdb
field: server.ip
- rename:
target_field: server.as.number
ignore_missing: true
field: server.as.asn
- rename:
field: server.as.organization_name
target_field: server.as.organization.name
ignore_missing: true
- append:
value: "{{source.ip}}"
if: ctx?.source?.ip != null
allow_duplicates: false
field: related.ip
- append:
value: "{{client.ip}}"
if: ctx?.client?.ip != null
allow_duplicates: false
field: related.ip
- append:
value: "{{server.ip}}"
if: ctx?.server?.ip != null
allow_duplicates: false
field: related.ip
- append:
field: related.user
value: "{{client.user.name}}"
allow_duplicates: false
if: ctx.client?.user?.name != null && ctx.client.user.name != '/'
- append:
field: related.user
value: "{{server.user.name}}"
allow_duplicates: false
if: ctx.server?.user?.name != null && ctx.server.user.name != '/'
- append:
value: "{{server.domain}}"
if: ctx?.server?.domain != null
allow_duplicates: false
field: related.hosts
- append:
value: "{{client.domain}}"
if: ctx?.client?.domain != null
allow_duplicates: false
field: related.hosts
on_failure:
- set:
field: error.message
value: "{{ _ingest.on_failure_message }}"