Skip to content

Commit

Permalink
Fixes #152 add support for cisco ACS
Browse files Browse the repository at this point in the history
  • Loading branch information
rfaircloth-splunk committed Dec 12, 2019
1 parent 428386d commit 1d533b7
Show file tree
Hide file tree
Showing 5 changed files with 220 additions and 0 deletions.
49 changes: 49 additions & 0 deletions docs/sources/Cisco/index.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,54 @@
# Vendor - Cisco

## Product - ACS

| Ref | Link |
|----------------|---------------------------------------------------------------------------------------------------------|
| Splunk Add-on | https://splunkbase.splunk.com/app/1811/ |
| Product Manual | https://community.cisco.com/t5/security-documents/acs-5-x-configuring-the-external-syslog-server/ta-p/3143143 |


### Sourcetypes

| sourcetype | notes |
|----------------|---------------------------------------------------------------------------------------------------------|
| cisco:acs | Aggregation used |

### Sourcetype and Index Configuration

| key | sourcetype | index | notes |
|----------------|----------------|----------------|----------------|
| cisco_acs | cisco:acs | netauth | None |


### Filter type

PATTERN MATCH

### Setup and Configuration

* No special steps required

### Options

| Variable | default | description |
|----------------|----------------|----------------|
| SC4S_LISTEN_CISCO_ACS_TCP_PORT | empty string | Enable a TCP port for this specific vendor product using the number defined expecting RFC5424 format |
| SC4S_LISTEN_CISCO_ACS_UDP_PORT | empty string | Enable a UDP port for this specific vendor product using the number defined expecting RFC5424 format |
| SC4S_ARCHIVE_CISCO_ACS | no | Enable archive to disk for this specific source |
| SC4S_DEST_CISCO_ACS_HEC | no | When Splunk HEC is disabled globally set to yes to enable this specific source |

### Verification

Use the following search to validate events are present

```
index=<asconfigured> sourcetype=cisco:acs
```

Verify timestamp, and host values match as expected


## Product - ASA (Pre Firepower)

| Ref | Link |
Expand Down
4 changes: 4 additions & 0 deletions package/etc/conf.d/filters/cisco/acs.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

filter f_cisco_acs {
program("CSCOacs.*");
};
109 changes: 109 additions & 0 deletions package/etc/conf.d/log_paths/p_rfc3164-cisco_acs.conf.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Cisco ACS
{{ $context := dict "port_id" "CISCO_ACS" "parser" "common"}}
{{ tmpl.Exec "t/source_network.t" $context }}

#This filter uses a field we set to prevent the original messages before aggregation from being
#sent to Splunk
filter f_cisco_acs_complete{
match("yes", value("ACS.COMPLETE") type(glob));
};

#This parser adds messages from ACS to a context without sending them
#forward to Splunk
parser acs_grouping {
csv-parser(
columns(PID, ACS.num, ACS.seq, MESSAGE)
delimiters(chars(" "))
flags(greedy)
);
grouping-by(
scope(program)
key("$PID")
trigger("$(+ ${ACS.seq} 1)" == "${ACS.num}")
sort-key("${ACS.seq}")
aggregate(
value("MESSAGE" "$(implode '' $(context-values ${MESSAGE}))")
value("ACS.COMPLETE" "yes")
)
timeout(10)
);
};

#The syslog message includes a date with nano seconds and TZ which is not in the header
#So must reparse the date
parser acs_event_time {
csv-parser(
columns(ACS.DATE, ACS.TIME, ACS.TZ, MESSAGE)
delimiters(chars(" "))
flags(greedy)
);

date-parser(
#YYYY- MM-DD hh:mm:ss:xxx +/-zh:zm
format("%Y-%m-%d %H:%M:%S.%f %z" )
template("${ACS.DATE} ${ACS.TIME} ${ACS.TZ}")
);
};
# The following is an inline template; we will use this to generate the actual log path
{{ define "log_path" }}
log {
{{- if eq (.) "yes"}}
source(s_DEFAULT);
filter(f_is_rfc3164);
filter(f_cisco_acs);
{{- end}}
{{- if eq (.) "no"}}
source (s_CISCO_ACS);
{{- end}}

parser(acs_grouping);

if {
filter(f_cisco_acs_complete);
parser(acs_event_time);
rewrite {
set("cisco_acs", value("fields.sc4s_vendor_product"));
r_set_splunk_dest_default(sourcetype("cisco:acs"), index("netauth"))
};

parser {p_add_context_splunk(key("cisco_acs")); };
parser (compliance_meta_by_source);

#We want to unset the fields we won't need, as this is copied into the
#disk queue for network destinations. This can be very disk expensive
#if we don't
rewrite {
set("$(template ${fields.sc4s_template} $(template t_msg_only))" value("MSG"));
unset(value("RAWMSG"));
unset(value("PROGRAM"));
unset(value("PID"));
unset(value("LEGACY_MSGHDR"));
unset(value("EPOCH"));
unset(value("VERSION"));
unset(value("TIMESECFRAC"));
groupunset(values("ACS.*"));
};

{{- if ((getenv "SC4S_DEST_SPLUNK_HEC_GLOBAL" "yes") | conv.ToBool) or (conv.ToBool (getenv "SC4S_DEST_CISCO_ACS_HEC" "no") | conv.ToBool) }}
destination(d_hec);
{{- end}}

{{- if (getenv "SC4S_ARCHIVE_GLOBAL") or (getenv "SC4S_ARCHIVE_CISCO_ACS") }}
destination(d_archive);
{{- end}}

flags(flow-control,final);
};


};
{{- end}}

{{- if or (or (getenv (print "SC4S_LISTEN_CISCO_ACS_TCP_PORT")) (getenv (print "SC4S_LISTEN_CISCO_ACS_UDP_PORT"))) (getenv (print "SC4S_LISTEN_CISCO_ACS_TLS_PORT")) }}

# Listen on the specified dedicated port(s) for CISCO_ACS traffic
{{tmpl.Exec "log_path" "no" }}
{{- end}}

# Listen on the default port (typically 514) for CISCO_ACS traffic
{{tmpl.Exec "log_path" "yes" }}
1 change: 1 addition & 0 deletions package/etc/context_templates/splunk_index.csv
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#checkpoint_splunk_web,index,netproxy
#checkpoint_splunk,index,netops
#checkpoint_splunk,index,netops
#cisco_acs,index,netauth
#cisco_asa,index,netfw
#cisco_ios,index,netops
#cisco_ise,index,netauth
Expand Down
57 changes: 57 additions & 0 deletions tests/test_cisco_acs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Copyright 2019 Splunk, Inc.
#
# Use of this source code is governed by a BSD-2-clause-style
# license that can be found in the LICENSE-BSD2 file or at
# https://opensource.org/licenses/BSD-2-Clause
import random

from jinja2 import Environment

from .sendmessage import *
from .splunkutils import *

env = Environment(extensions=['jinja2_time.TimeExtension'])


def test_cisco_acs_single(record_property, setup_wordlist, setup_splunk):
host = "{}-{}".format(random.choice(setup_wordlist), random.choice(setup_wordlist))

mt = env.from_string(
"{{ mark }} {% now 'utc', '%b %d %H:%M:%S' %} {{ host }} CSCOacs_Passed_Authentications 0765855540 1 0 2019-10-24 21:01:05.028 +00:00 0178632943 5202 NOTICE Device-Administration: Command Authorization succeeded, ACSVersion=acs-5.8.1.4-B.462.x86_64, ConfigVersionId=16489, Device IP Address=10.0.0.93, DestinationIPAddress=10.0.0.10, DestinationPort=49, UserName=nsdevman, CmdSet=[ CmdAV=show CmdArgAV=vpn-sessiondb CmdArgAV=full CmdArgAV=ra-ikev2-ipsec ], Protocol=Tacacs, MatchedCommandSet=fw3, RequestLatency=11, Type=Authorization, Privilege-Level=15, Authen-Type=ASCII, Service=None, User=nsdevman, Port=443, Remote-Address=10.0.0.15, Authen-Method=TacacsPlus, Service-Argument=shell, AcsSessionID=mnsvdcfpiuac03/359448835/9871764, AuthenticationIdentityStore=AD1, AuthenticationMethod=Lookup, SelectedAccessService=Default Device Admin, SelectedCommandSet=fw3, IdentityGroup=IdentityGroup:All Groups:SystemID, Step=13005 , Step=15008 , Step=15004 , Step=15012 , Step=15041 , Step=15004 , Step=15013 , Step=24210 , Step=24212 , Step=24432 , Step=24325 , Step=24313 , Step=24319 , Step=24323 , Step=24420 , Step=24355 , Step=24416 , Step=22037 , Step=15044 , Step=15035 , Step=15042 , Step=15036 , Step=15004 , Step=15018 , Step=13024 , Step=13034 , SelectedAuthenticationIdentityStores=Internal Users, NetworkDeviceName=devicenamehere, NetworkDeviceGroups=Device Type:All Device Types:Firewall:Cisco Systems:Firewall:ASA5545, NetworkDeviceGroups=Location:All Locations:MN, ServiceSelectionMatchedRule=TACACS, IdentityPolicyMatchedRule=Firewall, AuthorizationPolicyMatchedRule=nsdevman, AD-User-Candidate-Identities=nsdevman@ent.example.corp, AD-User-DNS-Domain=ent.example.corp, AD-User-NetBios-Name=AD-ENT, AD-User-Resolved-Identities=nsdevman@ent.example.corp, AD-User-Join-Point=ENT.example.CORP, AD-User-Resolved-DNs=CN=nsdevman\,OU=Service Accounts\,OU=CAO\,OU=ENT\,DC=ent\,DC=wfb\,DC=example\,DC=corp, StepData=10=nsdevman, StepData=11=ent.example.corp, StepData=12=example.corp, StepData=15=ent.example.corp, AD-Domain=ent.example.corp, IdentityAccessRestricted=false, UserIdentityGroup=IdentityGroup:All Groups:SystemID, Cisco-Firewall=Superuser, Firewall=Superuser, NetSec-CSM=User, NetSec-Logging=Engineer, Response={Type=Authorization; Author-Reply-Status=PassAdd; ExternalIdentityStoreName=AD1; }\n")
message = mt.render(mark="<165>", host=host)
sendsingle(message)

st = env.from_string("search index=netauth host=\"{{ host }}\" sourcetype=\"cisco:acs\" | head 11")
search = st.render(host=host)

resultCount, eventCount = splunk_single(setup_splunk, search)

record_property("host", host)
record_property("resultCount", resultCount)
record_property("message", message)

assert resultCount == 1

def test_cisco_acs_multi(record_property, setup_wordlist, setup_splunk):
host = "{}-{}".format(random.choice(setup_wordlist), random.choice(setup_wordlist))

mt = env.from_string(
"{{ mark }} {% now 'utc', '%b %d %H:%M:%S' %} {{ host }} CSCOacs_Passed_Authentications 0000000002 2 0 2011-08-01 22:32:53.032 +00:00 0000008450 5203 NOTICE Device-Administration: Session Authorization succeeded, ACSVersion=acs-5.2.0.26-B.3075, ConfigVersionId=117, Device IP Address=192.168.26.137, UserName=edward, CmdSet=[ CmdAV= ], Protocol=Tacacs, RequestLatency=10, NetworkDeviceName=switch, Type=Authorization, Privilege-Level=1, Authen-Type=ASCII, Service=Login, User=edward, Port=tty2, Remote-Address=10.78.167.190, Authen-Method=TacacsPlus, Service-Argument=shell, AcsSessionID=ACS41/101085887/112, AuthenticationIdentityStore=Internal Users, AuthenticationMethod=Lookup, SelectedAccessService=Default Device Admin, SelectedShellProfile=Permit Access, IdentityGroup=IdentityGroup:All Groups, Step=13005 , Step=15008 , Step=15004 , Step=15012 , Step=15041 , Step=15006 , Step=15013 , Step=24210 , Step=24212 , Step=22037 , Step=15044 , Step=15035 , Step=15042 , Step=15036 , Step=15004 , Step=15017 , Step=13034 ,\n")
message = mt.render(mark="<165>", host=host)
sendsingle(message)

mt = env.from_string(
"{{ mark }} {% now 'utc', '%b %d %H:%M:%S' %} {{ host }} CSCOacs_Passed_Authentications 0000000002 2 1 Step=13015 , SelectedAuthenticationIdentityStores=Internal Users, NetworkDeviceGroups=s1Migrated_NDGs:All s1Migrated_NDGs, NetworkDeviceGroups=Device Type:All Device Types, NetworkDeviceGroups=Location:All Locations, ServiceSelectionMatchedRule=Rule-2, IdentityPolicyMatchedRule=Default, AuthorizationPolicyMatchedRule=Rule-0, Action=Login, Privilege-Level=1, Authen-Type=ASCII, Service=Login, Remote-Address=10.78.167.190, UserIdentityGroup=IdentityGroup:All\n")
message = mt.render(mark="<165>", host=host)
sendsingle(message)

st = env.from_string("search index=netauth host=\"{{ host }}\" sourcetype=\"cisco:acs\" \"Step=13015\" | head 11")
search = st.render(host=host)

resultCount, eventCount = splunk_single(setup_splunk, search)

record_property("host", host)
record_property("resultCount", resultCount)
record_property("message", message)

assert resultCount == 1

0 comments on commit 1d533b7

Please sign in to comment.