Hello People,
I was searching for a solution to parse our NPS logs via filebeat and dissect and could not seems to find a related topic for this.
I am using fleet and a custom log integration to collect the logs
So here is my way to do it:
# 2022.Sept.09 fs Parse NPS/IAS/Radius logs
#
tags:
- Windows
- aai-nps
logtype: nps
#include_lines: ['^[0-9]{4}']
#exclude_lines: ['healthcheck','HealthMailbox']
processors:
# See https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/cc771748(v=ws.10)?redirectedfrom=MSDN
# https://www.radiusreporting.com/IAS-Standard-Attribute-Table.html
# https://www.deepsoftware.com/iasviewer/attributeslist.html
- dissect:
description: 'initial dissect with ending in action and reason'
tokenizer: '%{observer.ip},%{user.name},%{@timestamp},%{+@timestamp},%{service.name},%{observer.name},%{rest->}4136,%{event.action},4142,%{event.reason}'
field: "message"
target_prefix: ""
ignore_failure: true
overwrite_keys: true
ignore_missing: true
#
- dissect:
description: 'smallest dissect first'
tokenizer: '%{*p1},%{&p1},%{*p2},%{&p2},%{*p3},%{&p3},%{*p4},%{&p4},%{*p5},%{&p5},%{*p6},%{&p6},%{*p7},%{&p7},%{rest->}'
field: "rest"
target_prefix: ""
ignore_failure: true
overwrite_keys: true
ignore_missing: true
when:
regexp:
rest: '^.*,.*,'
#
- drop_fields:
fields: "rest"
ignore_missing: true
when:
equals:
rest: ''
#
- dissect:
description: 'iterate dissects that contain comma'
tokenizer: '%{*p1},%{&p1},%{rest->}'
field: "rest"
target_prefix: ""
ignore_failure: true
overwrite_keys: true
ignore_missing: true
when:
regexp:
rest: '^.*,.*,'
#
- drop_fields:
fields: "rest"
ignore_missing: true
when:
equals:
rest: ''
#
- dissect:
description: 'iterate dissects that contain comma'
tokenizer: '%{*p1},%{&p1},%{rest->}'
field: "rest"
target_prefix: ""
ignore_failure: true
overwrite_keys: true
ignore_missing: true
when:
regexp:
rest: '^.*,.*,'
#
- drop_fields:
fields: "rest"
ignore_missing: true
when:
equals:
rest: ''
#
- dissect:
description: 'iterate dissects that contain comma'
tokenizer: '%{*p1},%{&p1},%{rest->}'
field: "rest"
target_prefix: ""
ignore_failure: true
overwrite_keys: true
ignore_missing: true
when:
regexp:
rest: '^.*,.*,'
#
- drop_fields:
fields: "rest"
ignore_missing: true
when:
equals:
rest: ''
#
- dissect:
description: 'iterate dissects that contain comma'
tokenizer: '%{*p1},%{&p1},%{rest->}'
field: "rest"
target_prefix: ""
ignore_failure: true
overwrite_keys: true
ignore_missing: true
when:
regexp:
rest: '^.*,.*,'
#
- drop_fields:
fields: "rest"
ignore_missing: true
when:
equals:
rest: ''
#
- dissect:
description: 'iterate dissects that contain comma'
tokenizer: '%{*p1},%{&p1},%{rest->}'
field: "rest"
target_prefix: ""
ignore_failure: true
overwrite_keys: true
ignore_missing: true
when:
regexp:
rest: '^.*,.*,'
#
- drop_fields:
fields: "rest"
ignore_missing: true
when:
equals:
rest: ''
#
- dissect:
description: 'iterate dissects that contain comma'
tokenizer: '%{*p1},%{&p1},%{rest->}'
field: "rest"
target_prefix: ""
ignore_failure: true
overwrite_keys: true
ignore_missing: true
when:
regexp:
rest: '^.*,.*,'
#
- drop_fields:
fields: "rest"
ignore_missing: true
when:
equals:
rest: ''
#
- dissect:
description: 'iterate dissects that contain comma'
tokenizer: '%{*p1},%{&p1},%{rest->}'
field: "rest"
target_prefix: ""
ignore_failure: true
overwrite_keys: true
ignore_missing: true
when:
regexp:
rest: '^.*,.*,'
#
- drop_fields:
fields: "rest"
ignore_missing: true
when:
equals:
rest: ''
#
- dissect:
description: 'iterate dissects that contain comma'
tokenizer: '%{*p1},%{&p1},%{rest->}'
field: "rest"
target_prefix: ""
ignore_failure: true
overwrite_keys: true
ignore_missing: true
when:
regexp:
rest: '^.*,.*,'
#
- drop_fields:
fields: "rest"
ignore_missing: true
when:
equals:
rest: ''
#
- dissect:
description: 'iterate dissects that contain comma'
tokenizer: '%{*p1},%{&p1},%{rest->}'
field: "rest"
target_prefix: ""
ignore_failure: true
overwrite_keys: true
ignore_missing: true
when:
regexp:
rest: '^.*,.*,'
#
- drop_fields:
fields: "rest"
ignore_missing: true
when:
equals:
rest: ''
#
#
- dissect:
description: 'iterate dissects that contain comma'
tokenizer: '%{*p1},%{&p1},%{rest->}'
field: "rest"
target_prefix: ""
ignore_failure: true
overwrite_keys: true
ignore_missing: true
when:
regexp:
rest: '^.*,.*,'
#
- drop_fields:
fields: "rest"
ignore_missing: true
when:
equals:
rest: ''
#
- dissect:
description: 'iterate dissects that contain comma'
tokenizer: '%{*p1},%{&p1},%{rest->}'
field: "rest"
target_prefix: ""
ignore_failure: true
overwrite_keys: true
ignore_missing: true
when:
regexp:
rest: '^.*,.*,'
#
- drop_fields:
fields: "rest"
ignore_missing: true
when:
equals:
rest: ''
#
- dissect:
description: 'iterate dissects that contain comma'
tokenizer: '%{*p1},%{&p1},%{rest->}'
field: "rest"
target_prefix: ""
ignore_failure: true
overwrite_keys: true
ignore_missing: true
when:
regexp:
rest: '^.*,.*,'
#
- drop_fields:
fields: "rest"
ignore_missing: true
when:
equals:
rest: ''
#
- dissect:
description: 'iterate dissects that contain comma'
tokenizer: '%{*p1},%{&p1},%{rest->}'
field: "rest"
target_prefix: ""
ignore_failure: true
overwrite_keys: true
ignore_missing: true
when:
regexp:
rest: '^.*,.*,'
#
- drop_fields:
fields: "rest"
ignore_missing: true
when:
equals:
rest: ''
#
- dissect:
description: 'iterate dissects that contain comma'
tokenizer: '%{*p1},%{&p1},%{rest->}'
field: "rest"
target_prefix: ""
ignore_failure: true
overwrite_keys: true
ignore_missing: true
when:
regexp:
rest: '^.*,.*,'
#
- drop_fields:
fields: "rest"
ignore_missing: true
when:
equals:
rest: ''
#
# If you have more IAS fields, you might need to iterate more
#
- if:
has_fields: '4'
then:
- copy_fields:
fields:
- from: "4"
to: nps.nas-ip-address
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '8'
then:
- copy_fields:
fields:
- from: "8"
to: nps.framed-ip-address
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '11'
then:
- copy_fields:
fields:
- from: "11"
to: nps.filter-id
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '25'
then:
- copy_fields:
fields:
- from: "25"
to: nps.class
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '26'
then:
- copy_fields:
fields:
- from: "26"
to: nps.vendor-specific
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '30'
then:
- copy_fields:
fields:
- from: "30"
to: nps.called-station-id
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '31'
then:
- copy_fields:
fields:
- from: "31"
to: nps.calling-station-id
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '32'
then:
- copy_fields:
fields:
- from: "32"
to: nps.nas-identifier
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '40'
then:
- copy_fields:
fields:
- from: "40"
to: nps.acct-status-type
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '42'
then:
- copy_fields:
fields:
- from: "42"
to: nps.acct-input-octets
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '44'
then:
- copy_fields:
fields:
- from: "44"
to: nps.acct-session-id
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '50'
then:
- copy_fields:
fields:
- from: "50"
to: nps.acct-multi-ssn-id
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '61'
then:
- copy_fields:
fields:
- from: "61"
to: nps.nas-port-type
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '62'
then:
- copy_fields:
fields:
- from: "62"
to: nps.port-limit
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '64'
then:
- copy_fields:
fields:
- from: "64"
to: nps.tunnel-type
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '65'
then:
- copy_fields:
fields:
- from: "65"
to: nps.tunnel-medium-type
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '66'
then:
- copy_fields:
fields:
- from: "66"
to: nps.tunnel-client-endpt
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '77'
then:
- copy_fields:
fields:
- from: "77"
to: nps.connect-info
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '81'
then:
- copy_fields:
fields:
- from: "81"
to: nps.tunnel-pvt-group-id
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '126'
then:
- copy_fields:
fields:
- from: "126"
to: nps.ascend-route-preference
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '4108'
then:
- copy_fields:
fields:
- from: "4108"
to: client.ip
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '4116'
then:
- copy_fields:
fields:
- from: "4116"
to: nps.nas-manufacturer
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '4120'
then:
- copy_fields:
fields:
- from: "4120"
to: nps.ms-chap-domain
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '4127'
then:
- copy_fields:
fields:
- from: "4127"
to: nps.authentication-type
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '4128'
then:
- copy_fields:
fields:
- from: "4128"
to: nps.client-friendly-name
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '4129'
then:
- copy_fields:
fields:
- from: "4129"
to: nps.sam-account-name
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '4130'
then:
- copy_fields:
fields:
- from: "4130"
to: nps.fully-qualified-user-name
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '4132'
then:
- copy_fields:
fields:
- from: "4132"
to: nps.eap-friendly-name
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '4136'
then:
- copy_fields:
fields:
- from: "4136"
to: event.action
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '4142'
then:
- copy_fields:
fields:
- from: "4142"
to: event.reason
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '4149'
then:
- copy_fields:
fields:
- from: "4149"
to: nps.np-policy-name
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '4154'
then:
- copy_fields:
fields:
- from: "4154"
to: nps.proxy-policy-name
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '4155'
then:
- copy_fields:
fields:
- from: "4155"
to: nps.provider-type
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '8132'
then:
- copy_fields:
fields:
- from: "8132"
to: nps.ms-network-access-server-type
fail_on_error: false
ignore_missing: true
#
- if:
has_fields: '8138'
then:
- copy_fields:
fields:
- from: "8138"
to: nps.ms-machine-name
fail_on_error: false
ignore_missing: true
#
- if:
equals:
nps.ms-network-access-server-type: "0"
then:
- add_fields:
target: 'nps'
fields:
ms-network-access-server-type: ["0","Unspecified"]
- if:
equals:
nps.ms-network-access-server-type: "1"
then:
- add_fields:
target: 'nps'
fields:
ms-network-access-server-type: ["1","RDP"]
- if:
equals:
nps.ms-network-access-server-type: "2"
then:
- add_fields:
target: 'nps'
fields:
ms-network-access-server-type: ["2","Remote Access Server (VPN-Dial up)"]
- if:
equals:
nps.ms-network-access-server-type: "3"
then:
- add_fields:
target: 'nps'
fields:
ms-network-access-server-type: ["3","DHCP Server"]
#
- if:
equals:
nps.authentication-type: "1"
then:
- add_fields:
target: 'nps'
fields:
authentication-type: ["1","PAP"]
else:
- if:
equals:
nps.authentication-type: "2"
then:
- add_fields:
target: 'nps'
fields:
authentication-type: ["2","CHAP"]
else:
- if:
equals:
nps.authentication-type: "3"
then:
- add_fields:
target: 'nps'
fields:
authentication-type: ["3","MS-CHAP"]
else:
- if:
equals:
nps.authentication-type: "4"
then:
- add_fields:
target: 'nps'
fields:
authentication-type: ["4","MS-CHAPv2"]
else:
- if:
equals:
nps.authentication-type: "5"
then:
- add_fields:
target: 'nps'
fields:
authentication-type: ["5","EAP"]
else:
- if:
equals:
nps..authentication-type: "7"
then:
- add_fields:
target: 'nps'
fields:
authentication-type: ["7","Unauthenticated"]
else:
- if:
equals:
nps..authentication-type: "8"
then:
- add_fields:
target: 'nps'
fields:
authentication-type: ["8","Extension"]
# There are other types not included above ^
#
- if:
equals:
nps.provider-type: "1"
then:
- add_fields:
target: 'nps'
fields:
provider-type: ["0","None"]
else:
- if:
equals:
nps.provider-type: "1"
then:
- add_fields:
target: 'nps'
fields:
provider-type: ["1","Windows"]
else:
- if:
equals:
nps.provider-type: "2"
then:
- add_fields:
target: 'nps'
fields:
provider-type: ["2","RADIUS Proxy"]
#
- if:
equals:
event.action: "1"
then:
- add_fields:
target: 'event'
fields:
action: ["1","Accept-Request"]
else:
- if:
equals:
event.action: "2"
then:
- add_fields:
target: 'event'
fields:
action: ["2","Access-Accept"]
else:
- if:
equals:
event.action: "3"
then:
- add_fields:
target: 'event'
fields:
action: ["3","Access-Reject"]
else:
- if:
equals:
event.action: "4"
then:
- add_fields:
target: 'event'
fields:
action: ["4","Accounting-Request"]
# There are other types not included
# tunnel-types:
#1: Point-to-Point Tunneling Protocol (PPTP)
#2: Layer Two Forwarding (L2F)
#3: Layer Two Tunneling Protocol (L2TP)
#4: Ascend Tunnel Management Protocol (ATMP)
#5: Virtual Tunneling Protocol (VTP)
#6: IP Authentication Header in the Tunnel-mode (AH)
#7: IP-in-IP Encapsulation (IP-IP)
#8: Minimal IP-in-IP Encapsulation (MIN-IP-IP)
#9: IP Encapsulating Security Payload in the Tunnel-mode (ESP)
#10: Generic Route Encapsulation (GRE)
#11: Bay Dial Virtual Services (DVS)
#12: IP-in-IP Tunneling
#13: Virtual LANs (VLAN)
#79617: Secure Socket Tunneling Protocol (SSTP)
- if:
equals:
nps.tunnel-type: "13"
then:
- add_fields:
target: 'nps'
fields:
tunnel-type: ["13","Virtual LANs (VLAN)"]
#
- if:
equals:
nps.nas-manufacturer: "0"
then:
- add_fields:
target: 'nps'
fields:
nas-manufacturer: ["0","RADIUS Standard"]
#
- if:
equals:
nps.tunnel-medium-type: "1"
then:
- add_fields:
target: 'nps'
fields:
tunnel-medium-type: ["1","ipv4"]
- if:
equals:
nps.tunnel-medium-type: "2"
then:
- add_fields:
target: 'nps'
fields:
tunnel-medium-type: ["2","ipv6"]
- if:
equals:
nps.tunnel-medium-type: "6"
then:
- add_fields:
target: 'nps'
fields:
tunnel-medium-type: ["6","802 (includes all 802 media plus Ethernet canonical format)"]
#nas-port-type
- if:
equals:
nps.nas-port-type: "5"
then:
- add_fields:
target: 'nps'
fields:
nas-port-type: ["5","VPN"]
- if:
equals:
nps.nas-port-type: "15"
then:
- add_fields:
target: 'nps'
fields:
nas-port-type: ["15","Ethernet"]
- if:
equals:
nps.nas-port-type: "18"
then:
- add_fields:
target: 'nps'
fields:
nas-port-type: ["18","Wireless - Other"]
- if:
equals:
nps.nas-port-type: "19"
then:
- add_fields:
target: 'nps'
fields:
nas-port-type: ["19","Wireless - IEEE 802.11"]
# Evt reason
- if:
equals:
event.reason: "0"
then:
- add_fields:
target: 'event'
fields:
reason: ["0","success"]
- if:
equals:
event.reason: "1"
then:
- add_fields:
target: 'event'
fields:
reason: ["1","internal_error"]
- if:
equals:
event.reason: "2"
then:
- add_fields:
target: 'event'
fields:
reason: ["2","access_denied"]
- if:
equals:
event.reason: "3"
then:
- add_fields:
target: 'event'
fields:
reason: ["3","malformed_request"]
- if:
equals:
event.reason: "4"
then:
- add_fields:
target: 'event'
fields:
reason: ["4","global_catalog_unavailable"]
- if:
equals:
event.reason: "5"
then:
- add_fields:
target: 'event'
fields:
reason: ["5","domain_unavailable"]
- if:
equals:
event.reason: "6"
then:
- add_fields:
target: 'event'
fields:
reason: ["6","server_unavailable"]
- if:
equals:
event.reason: "7"
then:
- add_fields:
target: 'event'
fields:
reason: ["7","no_such_domain"]
- if:
equals:
event.reason: "8"
then:
- add_fields:
target: 'event'
fields:
reason: ["8","no_such_user"]
- if:
equals:
event.reason: "16"
then:
- add_fields:
target: 'event'
fields:
reason: ["16","auth_failure"]
- if:
equals:
event.reason: "21"
then:
- add_fields:
target: 'event'
fields:
reason: ["21","An NPS extension dynamic link library (DLL) that is installed on the NPS server rejected the connection request."]
- if:
equals:
event.reason: "34"
then:
- add_fields:
target: 'event'
fields:
reason: ["34","account_disabled"]
- if:
equals:
event.reason: "35"
then:
- add_fields:
target: 'event'
fields:
reason: ["35","account_expired"]
- if:
equals:
event.reason: "36"
then:
- add_fields:
target: 'event'
fields:
reason: ["36","account_locked_out"]
- if:
equals:
event.reason: "48"
then:
- add_fields:
target: 'event'
fields:
reason: ["48","no_policy_match"]
# acct-status-type
- if:
has_fields: "acct-status-type"
then:
- if:
equals:
nps.acct-status-type: "1"
then:
- add_fields:
target: 'nps'
fields:
acct-status-type: ["1","Start"]
- if:
equals:
nps.acct-status-type: "2"
then:
- add_fields:
target: 'nps'
fields:
acct-status-type: ["2","Stop"]
- if:
equals:
nps.acct-status-type: "3"
then:
- add_fields:
target: 'nps'
fields:
acct-status-type: ["3","Interim Update"]
- if:
equals:
nps.acct-status-type: "7"
then:
- add_fields:
target: 'nps'
fields:
acct-status-type: ["7","Accounting-On"]
- if:
equals:
nps.acct-status-type: "8"
then:
- add_fields:
target: 'nps'
fields:
acct-status-type: ["8","Accounting-Off"]
- if:
equals:
nps.acct-status-type: "9"
then:
- add_fields:
target: 'nps'
fields:
acct-status-type: ["9","Tunnel-Start"]
- if:
equals:
nps.acct-status-type: "10"
then:
- add_fields:
target: 'nps'
fields:
acct-status-type: ["10","Tunnel-Stop"]
- if:
equals:
nps.acct-status-type: "11"
then:
- add_fields:
target: 'nps'
fields:
acct-status-type: ["11","Tunnel-Reject"]
- if:
equals:
nps.acct-status-type: "12"
then:
- add_fields:
target: 'nps'
fields:
acct-status-type: ["12","Tunnel-Link-Start"]
- if:
equals:
nps.acct-status-type: "13"
then:
- add_fields:
target: 'nps'
fields:
acct-status-type: ["13","Tunnel-Link-Stop"]
- if:
equals:
nps.acct-status-type: "14"
then:
- add_fields:
target: 'nps'
fields:
acct-status-type: ["14","Tunnel-Link-Reject"]
- if:
equals:
nps.acct-status-type: "15"
then:
- add_fields:
target: 'nps'
fields:
acct-status-type: ["15","Failed"]
#
- copy_fields:
fields:
- from: client.ip
to: source.ip
- from: client.ip
to: related.ip
- from: nps.ms-machine-name
to: related.ip
- from: nps.framed-ip-address
to: related.ip
- from: user.name
to: related.user
- from: source.ip
to: related.ip
fail_on_error: false
ignore_missing: true
#
# Drop unneeded fields
#
- drop_fields:
fields: ["4","8","11","25","26","30","31","32","40","44","50","61","62","64","65","66","77","81","126","4108","4116","4120","4127","4128","4129","4130","4132","4142","4149","4154","4155","8138"]
ignore_missing: true
# Last
- drop_fields:
fields: "rest"
ignore_missing: true
when:
equals:
rest: ''
I tried to keep close to ECS but not NPS fields have an equivalent.
I did not populated al fields since not all are used.
Any improvements or suggestions are welcomed
Also I would like to compare(performance related) to a GROK version