├── images ├── pfSense dashboard.png ├── suricata dashboard.png └── suricata eve settings.png ├── config └── logstash │ ├── pipeline │ ├── 30-outputs.conf │ ├── 01-inputs.conf │ ├── 10-suricata.conf │ ├── 10-syslog.conf │ └── 11-pfsense.conf │ └── patterns │ └── pfsense2-4.grok ├── kibana ├── dashboards.json └── visualizations.json ├── README.md └── docker-compose.yml /images/pfSense dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evaluationcopy/pfsense-suricata-elk-docker/HEAD/images/pfSense dashboard.png -------------------------------------------------------------------------------- /images/suricata dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evaluationcopy/pfsense-suricata-elk-docker/HEAD/images/suricata dashboard.png -------------------------------------------------------------------------------- /images/suricata eve settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evaluationcopy/pfsense-suricata-elk-docker/HEAD/images/suricata eve settings.png -------------------------------------------------------------------------------- /config/logstash/pipeline/30-outputs.conf: -------------------------------------------------------------------------------- 1 | output { 2 | if [type] == "syslog" { 3 | elasticsearch { 4 | hosts => elasticsearch 5 | index => "logstash-pfsense-%{+YYYY.MM.dd}" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /config/logstash/pipeline/01-inputs.conf: -------------------------------------------------------------------------------- 1 | #tcp syslog stream via 1514 2 | input { 3 | tcp { 4 | type => "syslog" 5 | port => 1514 6 | } 7 | } 8 | #udp syslogs stream via 1514 9 | input { 10 | udp { 11 | type => "syslog" 12 | port => 1514 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /config/logstash/pipeline/10-suricata.conf: -------------------------------------------------------------------------------- 1 | filter { 2 | if [type] == "SuricataIDPS" { 3 | date { 4 | match => [ "timestamp", "ISO8601" ] 5 | } 6 | ruby { 7 | code => "if event['event_type'] == 'fileinfo'; event['fileinfo']['type']=event['fileinfo']['magic'].to_s.split(',')[0]; end;" 8 | } 9 | } 10 | 11 | #custom remove dns entries 12 | if [event_type] == "dns" { 13 | drop { } 14 | } 15 | } -------------------------------------------------------------------------------- /config/logstash/pipeline/10-syslog.conf: -------------------------------------------------------------------------------- 1 | filter { 2 | if [type] == "syslog" { 3 | #change to pfSense ip address 4 | if [host] =~ /172\.18\.0\.1/ { 5 | mutate { 6 | add_tag => ["PFSense", "Ready"] 7 | } 8 | } 9 | if "Ready" not in [tags] { 10 | mutate { 11 | add_tag => [ "syslog" ] 12 | } 13 | } 14 | } 15 | } 16 | filter { 17 | if [type] == "syslog" { 18 | mutate { 19 | remove_tag => "Ready" 20 | } 21 | } 22 | } 23 | filter { 24 | if "syslog" in [tags] { 25 | grok { 26 | match => { "message" => "%{SYSLOGTIMESTAMP:syslog_timestamp} %{SYSLOGHOST:syslog_hostname} %{DATA:syslog_program}(?:\[%{POSINT:syslog_pid}\])?: %{GREEDYDATA:syslog_message}" } 27 | add_field => [ "received_at", "%{@timestamp}" ] 28 | add_field => [ "received_from", "%{host}" ] 29 | } 30 | syslog_pri { } 31 | date { 32 | match => [ "syslog_timestamp", "MMM d HH:mm:ss", "MMM dd HH:mm:ss" ] 33 | locale => "en" 34 | } 35 | if !("_grokparsefailure" in [tags]) { 36 | mutate { 37 | replace => [ "@source_host", "%{syslog_hostname}" ] 38 | replace => [ "@message", "%{syslog_message}" ] 39 | } 40 | } 41 | mutate { 42 | remove_field => [ "syslog_hostname", "syslog_message", "syslog_timestamp" ] 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /config/logstash/pipeline/11-pfsense.conf: -------------------------------------------------------------------------------- 1 | filter { 2 | if "PFSense" in [tags] { 3 | grok { 4 | add_tag => [ "firewall" ] 5 | match => [ "message", "<(?.*)>(?(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\s+(?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9]) (?:2[0123]|[01]?[0-9]):(?:[0-5][0-9]):(?:[0-5][0-9])) (?.*?): (?.*)" ] 6 | } 7 | mutate { 8 | gsub => ["datetime"," "," "] 9 | } 10 | date { 11 | match => [ "datetime", "MMM dd HH:mm:ss" ] 12 | timezone => "America/New_York" 13 | } 14 | mutate { 15 | replace => [ "message", "%{msg}" ] 16 | } 17 | mutate { 18 | remove_field => [ "msg", "datetime" ] 19 | } 20 | if [prog] !~ /^filterlog$/ and [prog] !~ /^suricata/ { 21 | drop { } 22 | } 23 | if [prog] =~ /^suricata/ { 24 | mutate { 25 | add_tag => [ "SuricataIDPS" ] 26 | } 27 | if [message] =~ /^\{/ { 28 | mutate { 29 | gsub => [ "message", "[\u0000]", "\\\"}}" ] 30 | } 31 | json { 32 | source => "message" 33 | } 34 | } 35 | geoip { 36 | add_tag => [ "GeoIP" ] 37 | source => "src_ip" 38 | } 39 | } 40 | if [prog] =~ /^filterlog$/ { 41 | mutate { 42 | remove_field => [ "msg", "datetime" ] 43 | } 44 | grok { 45 | patterns_dir => "/usr/share/logstash/patterns" 46 | match => [ "message", "%{PFSENSE_LOG_DATA}%{PFSENSE_IP_SPECIFIC_DATA}%{PFSENSE_IP_DATA}%{PFSENSE_PROTOCOL_DATA}", 47 | "message", "%{PFSENSE_LOG_DATA}%{PFSENSE_IPv4_SPECIFIC_DATA_ECN}%{PFSENSE_IP_DATA}%{PFSENSE_PROTOCOL_DATA}" ] 48 | } 49 | mutate { 50 | lowercase => [ 'proto' ] 51 | } 52 | geoip { 53 | add_tag => [ "GeoIP" ] 54 | source => "src_ip" 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /kibana/dashboards.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "_id": "3cc16000-92a3-11e7-b4f8-6947ec97a76c", 4 | "_type": "dashboard", 5 | "_source": { 6 | "title": "pfSense", 7 | "hits": 0, 8 | "description": "pfSense Dashboard", 9 | "panelsJSON": "[{\"embeddableConfig\":{\"mapCenter\":[13.581920900545857,12.656250000000002],\"mapZoom\":1},\"gridData\":{\"h\":25,\"i\":\"1\",\"w\":20,\"x\":28,\"y\":0},\"id\":\"f636e740-92a2-11e7-b4f8-6947ec97a76c\",\"panelIndex\":\"1\",\"type\":\"visualization\",\"version\":\"6.3.0\"},{\"gridData\":{\"h\":25,\"i\":\"2\",\"w\":16,\"x\":12,\"y\":0},\"id\":\"b3c31a50-92c5-11e7-87a2-7940ffb808f9\",\"panelIndex\":\"2\",\"type\":\"visualization\",\"version\":\"6.3.0\"},{\"embeddableConfig\":{\"spy\":{\"mode\":{\"fill\":false,\"name\":null}},\"vis\":{\"defaultColors\":{\"0 - 200\":\"rgb(0,104,55)\",\"1000 - 1200\":\"rgb(234,88,57)\",\"1200 - 1400\":\"rgb(165,0,38)\",\"200 - 400\":\"rgb(76,176,93)\",\"400 - 600\":\"rgb(183,224,117)\",\"600 - 800\":\"rgb(255,255,190)\",\"800 - 1000\":\"rgb(253,191,111)\"}}},\"gridData\":{\"h\":25,\"i\":\"3\",\"w\":12,\"x\":0,\"y\":0},\"id\":\"33c9cd60-92c7-11e7-87a2-7940ffb808f9\",\"panelIndex\":\"3\",\"type\":\"visualization\",\"version\":\"6.3.0\"},{\"embeddableConfig\":{\"vis\":{\"legendOpen\":false}},\"gridData\":{\"h\":25,\"i\":\"4\",\"w\":48,\"x\":0,\"y\":25},\"id\":\"ed689730-9379-11e7-851b-4be14ad14ed6\",\"panelIndex\":\"4\",\"type\":\"visualization\",\"version\":\"6.3.0\"}]", 10 | "optionsJSON": "{\"darkTheme\":true,\"useMargins\":false}", 11 | "version": 1, 12 | "timeRestore": false, 13 | "kibanaSavedObjectMeta": { 14 | "searchSourceJSON": "{\"filter\":[],\"highlightAll\":true,\"version\":true,\"query\":{\"language\":\"lucene\",\"query\":{\"match_all\":{}}}}" 15 | } 16 | } 17 | }, 18 | { 19 | "_id": "5db43ee0-7e2a-11e8-b267-4d1688b0bab4", 20 | "_type": "dashboard", 21 | "_source": { 22 | "title": "Suricata", 23 | "hits": 0, 24 | "description": "pfSense Dashboard", 25 | "panelsJSON": "[{\"panelIndex\":\"7\",\"gridData\":{\"x\":25,\"y\":0,\"w\":23,\"h\":25,\"i\":\"7\"},\"embeddableConfig\":{\"mapCenter\":[37.782941450067156,8.68909996468574],\"mapZoom\":1},\"id\":\"fcdc1200-7e29-11e8-b267-4d1688b0bab4\",\"type\":\"visualization\",\"version\":\"6.3.0\"},{\"panelIndex\":\"10\",\"gridData\":{\"x\":8,\"y\":0,\"w\":17,\"h\":25,\"i\":\"10\"},\"embeddableConfig\":{},\"id\":\"df49d9e0-7e2c-11e8-b267-4d1688b0bab4\",\"type\":\"visualization\",\"version\":\"6.3.0\"},{\"panelIndex\":\"11\",\"gridData\":{\"x\":0,\"y\":25,\"w\":25,\"h\":22,\"i\":\"11\"},\"embeddableConfig\":{\"mapCenter\":[52.482780222078226,1.40625],\"mapZoom\":1},\"id\":\"135aae00-7e30-11e8-b267-4d1688b0bab4\",\"type\":\"visualization\",\"version\":\"6.3.0\"},{\"panelIndex\":\"12\",\"gridData\":{\"x\":25,\"y\":25,\"w\":23,\"h\":22,\"i\":\"12\"},\"embeddableConfig\":{},\"id\":\"e5b1e0d0-7e30-11e8-b267-4d1688b0bab4\",\"type\":\"visualization\",\"version\":\"6.3.0\"},{\"panelIndex\":\"13\",\"gridData\":{\"x\":0,\"y\":0,\"w\":8,\"h\":25,\"i\":\"13\"},\"version\":\"6.3.0\",\"type\":\"visualization\",\"id\":\"7a16cea0-7e3d-11e8-a400-fb1b13f7ba25\",\"embeddableConfig\":{}}]", 26 | "optionsJSON": "{\"darkTheme\":true,\"useMargins\":false}", 27 | "version": 1, 28 | "timeRestore": false, 29 | "kibanaSavedObjectMeta": { 30 | "searchSourceJSON": "{\"filter\":[],\"highlightAll\":true,\"version\":true,\"query\":{\"language\":\"lucene\",\"query\":{\"match_all\":{}}}}" 31 | } 32 | } 33 | } 34 | ] -------------------------------------------------------------------------------- /config/logstash/patterns/pfsense2-4.grok: -------------------------------------------------------------------------------- 1 | # GROK match pattern for logstash.conf filter: %{PFSENSE_LOG_DATA}%{PFSENSE_IP_SPECIFIC_DATA}%{PFSENSE_IP_DATA}%{PFSENSE_PROTOCOL_DATA} 2 | # GROK Custom Patterns (add to patterns directory and reference in GROK filter for pfSense events): 3 | # GROK Patterns for pfSense 2.3 Logging Format 4 | # 5 | # Created 27 Jan 2015 by J. Pisano (Handles TCP, UDP, and ICMP log entries) 6 | # Edited 14 Feb 2015 by Elijah Paul elijah.paul@gmail.com 7 | # Edited 10 Mar 2015 by Bernd Zeimetz 8 | # Edited 02 Jul 2018 by D Sharone 9 | # taken from https://gist.github.com/elijahpaul/f5f32d4e914dcb7fedd2 10 | # - adding PFSENSE_ prefix 11 | # - adding carp patterns 12 | # 13 | # Usage: Use with following GROK match pattern 14 | # 15 | # %{PFSENSE_LOG_DATA}%{PFSENSE_IP_SPECIFIC_DATA}%{PFSENSE_IP_DATA}%{PFSENSE_PROTOCOL_DATA} 16 | 17 | # pfsense 2.4 modification: sub_rule is optional. 18 | PFSENSE_LOG_DATA (%{INT:rule}),(%{INT:sub_rule})?,,(%{INT:tracker}),(%{DATA:iface}),(%{WORD:reason}),(%{WORD:action}),(%{WORD:direction}),(%{INT:ip_ver}), 19 | PFSENSE_IP_SPECIFIC_DATA (%{PFSENSE_IPv4_SPECIFIC_DATA}|%{PFSENSE_IPv6_SPECIFIC_DATA}) 20 | PFSENSE_IPv4_SPECIFIC_DATA (%{BASE16NUM:tos}),,(%{INT:ttl}),(%{INT:id}),(%{INT:offset}),(%{WORD:flags}),(%{INT:proto_id}),(%{WORD:proto}), 21 | PFSENSE_IPv4_SPECIFIC_DATA_ECN (%{BASE16NUM:tos}),(%{INT:ecn}),(%{INT:ttl}),(%{INT:id}),(%{INT:offset}),(%{WORD:flags}),(%{INT:proto_id}),(%{WORD:proto}), 22 | PFSENSE_IPv6_SPECIFIC_DATA (%{BASE16NUM:class}),(%{DATA:flow_label}),(%{INT:hop_limit}),(%{WORD:proto}),(%{INT:proto_id}), 23 | PFSENSE_IP_DATA (%{INT:length}),(%{IP:src_ip}),(%{IP:dest_ip}), 24 | PFSENSE_PROTOCOL_DATA (%{PFSENSE_TCP_DATA}|%{PFSENSE_UDP_DATA}|%{PFSENSE_ICMP_DATA}|%{PFSENSE_CARP_DATA}) 25 | PFSENSE_TCP_DATA (%{INT:src_port}),(%{INT:dest_port}),(%{INT:data_length}),(%{WORD:tcp_flags}),(%{INT:sequence_number}),(%{INT:ack_number}),(%{INT:tcp_window}),(%{DATA:urg_data}),(%{DATA:tcp_options}) 26 | PFSENSE_UDP_DATA (%{INT:src_port}),(%{INT:dest_port}),(%{INT:data_length}) 27 | PFSENSE_ICMP_DATA (%{PFSENSE_ICMP_TYPE}%{PFSENSE_ICMP_RESPONSE}) 28 | PFSENSE_ICMP_TYPE (?(request|reply|unreachproto|unreachport|unreach|timeexceed|paramprob|redirect|maskreply|needfrag|tstamp|tstampreply)), 29 | PFSENSE_ICMP_RESPONSE (%{PFSENSE_ICMP_ECHO_REQ_REPLY}|%{PFSENSE_ICMP_UNREACHPORT}| %{PFSENSE_ICMP_UNREACHPROTO}|%{PFSENSE_ICMP_UNREACHABLE}|%{PFSENSE_ICMP_NEED_FLAG}|%{PFSENSE_ICMP_TSTAMP}|%{PFSENSE_ICMP_TSTAMP_REPLY}) 30 | PFSENSE_ICMP_ECHO_REQ_REPLY (%{INT:icmp_echo_id}),(%{INT:icmp_echo_sequence}) 31 | PFSENSE_ICMP_UNREACHPORT (%{IP:icmp_unreachport_dest_ip}),(%{WORD:icmp_unreachport_protocol}),(%{INT:icmp_unreachport_port}) 32 | PFSENSE_ICMP_UNREACHPROTO (%{IP:icmp_unreach_dest_ip}),(%{WORD:icmp_unreachproto_protocol}) 33 | PFSENSE_ICMP_UNREACHABLE (%{GREEDYDATA:icmp_unreachable}) 34 | PFSENSE_ICMP_NEED_FLAG (%{IP:icmp_need_flag_ip}),(%{INT:icmp_need_flag_mtu}) 35 | PFSENSE_ICMP_TSTAMP (%{INT:icmp_tstamp_id}),(%{INT:icmp_tstamp_sequence}) 36 | PFSENSE_ICMP_TSTAMP_REPLY (%{INT:icmp_tstamp_reply_id}),(%{INT:icmp_tstamp_reply_sequence}),(%{INT:icmp_tstamp_reply_otime}),(%{INT:icmp_tstamp_reply_rtime}),(%{INT:icmp_tstamp_reply_ttime}) 37 | 38 | PFSENSE_CARP_DATA (%{WORD:carp_type}),(%{INT:carp_ttl}),(%{INT:carp_vhid}),(%{INT:carp_version}),(%{INT:carp_advbase}),(%{INT:carp_advskew}) 39 | 40 | DHCPD (%{DHCPDISCOVER}|%{DHCPOFFER}|%{DHCPREQUEST}|%{DHCPACK}|%{DHCPINFORM}|%{DHCPRELEASE}) 41 | DHCPDISCOVER %{WORD:dhcp_action} from %{COMMONMAC:dhcp_client_mac}%{SPACE}(\(%{GREEDYDATA:dhcp_client_hostname}\))? via (?[0-9a-z_]*)(: %{GREEDYDATA:dhcp_load_balance})? 42 | DHCPOFFER %{WORD:dhcp_action} on %{IPV4:dhcp_client_ip} to %{COMMONMAC:dhcp_client_mac}%{SPACE}(\(%{GREEDYDATA:dhcp_client_hostname}\))? via (?[0-9a-z_]*) 43 | DHCPREQUEST %{WORD:dhcp_action} for %{IPV4:dhcp_client_ip}%{SPACE}(\(%{IPV4:dhcp_ip_unknown}\))? from %{COMMONMAC:dhcp_client_mac}%{SPACE}(\(%{GREEDYDATA:dhcp_client_hostname}\))? via (?[0-9a-z_]*)(: %{GREEDYDATA:dhcp_request_message})? 44 | DHCPACK %{WORD:dhcp_action} on %{IPV4:dhcp_client_ip} to %{COMMONMAC:dhcp_client_mac}%{SPACE}(\(%{GREEDYDATA:dhcp_client_hostname}\))? via (?[0-9a-z_]*) 45 | DHCPINFORM %{WORD:dhcp_action} from %{IPV4:dhcp_client_ip} via %(?[0-9a-z_]*) 46 | DHCPRELEASE %{WORD:dhcp_action} of %{IPV4:dhcp_client_ip} from %{COMMONMAC:dhcp_client_mac}%{SPACE}(\(%{GREEDYDATA:dhcp_client_hostname}\))? via 47 | 48 | #stuff I added 49 | 50 | PFSENSE_APP (%{DATA:pfsense_APP}): 51 | PFSENSE_APP_DATA (%{PFSENSE_APP_LOGOUT}|%{PFSENSE_APP_LOGIN}|%{PFSENSE_APP_ERROR}|%{PFSENSE_APP_GEN}) 52 | PFSENSE_APP_LOGIN (%{DATA:pfsense_ACTION}) for user \'(%{DATA:pfsense_USER})\' from: (%{GREEDYDATA:pfsense_REMOTE_IP}) 53 | PFSENSE_APP_LOGOUT User (%{DATA:pfsense_ACTION}) for user \'(%{DATA:pfsense_USER})\' from: (%{GREEDYDATA:pfsense_REMOTE_IP}) 54 | PFSENSE_APP_ERROR webConfigurator (%{DATA:pfsense_ACTION}) for \'(%{DATA:pfsense_USER})\' from (%{GREEDYDATA:pfsense_REMOTE_IP}) 55 | PFSENSE_APP_GEN (%{GREEDYDATA:pfsense_ACTION}) 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pfsense-suricata-elk-docker 2 | Ties pfSense with Suricata into ELK (Elasticsearch, logstash, and kibana) using docker-compose 3 | 4 | Tested with Elasticsearch 6.3.0 and pfSense 2.4.3-RELEASE-p1 using docker for windows 5 | 6 | The idea here is to use the plain docker images published by [Docker@Elastic](https://www.docker.elastic.co/#). We use the docker-compose.yml to specify the locations on disk to map, such as the data directory for elasticsearch and the config directories for logstash. 7 | 8 | In the future, upgraging the version of elastic should be as easy as setting the environmental variables defined below. 9 | 10 | # Installation 11 | 12 | ## Docker 13 | 14 | Install [Docker for Windows](https://docs.docker.com/docker-for-windows/install/). 15 | 16 | Download the [pfsense-suricata-elk-docker repo](https://github.com/evaluationcopy/pfsense-suricata-elk-docker) contents. 17 | 18 | Open a command prompt in the directory of the git repo. 19 | 20 | Run the following commands to set the elastic version environment variables: 21 | 22 | set ELASTIC_VERSION=6.3.0 23 | 24 | set TAG=6.3.0 25 | 26 | Edit the file docker-compose.yml, change the IP address 192.168.1.13 to the local IP that will be running docker (this PC). You'll notice both elastic and kibana use 127.0.0.1 and will only be available to the local machine while logstash will be available from your local network. You can update kibana to be available to your local network as well by updating it's IP address. 27 | 28 | Stand up all the docker containers specified in the docker-compose.yml: 29 | 30 | docker-compose up 31 | 32 | At this point, windows firewall should have asked to you allow docker to open the port. Allow it. 33 | 34 | Check out kibana at http://127.0.0.1:5601 35 | 36 | Edit /config/logstash/pipeline/10-syslog.conf and change the host conditional on line 4 to be your pfSense IP address. 37 | 38 | These changes will take effect when you restart logstash. 39 | 40 | If you didn't get any docker errors, then awesome. Let's run it in detached mode now: 41 | 42 | docker-compose up -d 43 | 44 | Whenever you need to bring it down: 45 | 46 | docker-compose down 47 | 48 | You can also bring the services up individually: 49 | 50 | docker-compose up logstash 51 | 52 | ## pfSense 53 | 54 | Enable remote logging in the pfSense web UI by going to: 55 | 56 | Status -> System Logs -> Settings 57 | 58 | In Remote Logging Options, check "Enable Remote Logging", and add your remote Logstash server to the "Remote log servers". For example: 59 | 192.168.1.13:1514 60 | 61 | Finally, check the "Everything" checkbox for "Remote Syslog Contents". Suricata won't log eve json unless "Everything" is chosen. 62 | 63 | You may need to skim some of the entries in kibana to see if you got this right, as the source ip may not be your routers ip, due to running through docker. You can do this once pfSense is configured to log to LogStash. In kibana, under Dev Tools -> Console press the play button. 64 | 65 | ## Suricata 66 | 67 | Enable Suricata logging to the syslog in pfSense web UI by going to: 68 | 69 | Services -> Suricata -> Interfaces 70 | 71 | Click the edit button for the interface you want logged. 72 | 73 | Under WAN Settings sroll down to EVE Output Settings 74 | 75 | Copy these settings: 76 | 77 | ![alt text](https://raw.githubusercontent.com/evaluationcopy/pfsense-suricata-elk-docker/master/images/suricata%20eve%20settings.png) 78 | 79 | Click Save and restart the Suricata interface. 80 | 81 | ## Kibana 82 | Import the kibana/visualizations.json and kibana/dashboard.json files. A easy google. 83 | 84 | You may want to edit the filters in the kibana visualizations once you import them. I've filtered my lan interface out of the firewall logs to clean up some noise. 85 | 86 | pfSense dashboard 87 | 88 | ![alt text](https://raw.githubusercontent.com/evaluationcopy/pfsense-suricata-elk-docker/master/images/pfSense%20dashboard.png) 89 | 90 | Suricata dashboard 91 | 92 | ![alt text](https://raw.githubusercontent.com/evaluationcopy/pfsense-suricata-elk-docker/master/images/suricata%20dashboard.png) 93 | 94 | # Notes 95 | 96 | Suricata seems to log both the eve json and it's regular output into the syslog. 97 | 98 | Logstash has a parsing error, which I believe is related to the Suricata non-json logging. This doesn't stop it from logging, but future work could remove the error. 99 | 100 | Some numeric data in elasticsearch appears to be logged as a string type, such as dest_port. Work can be done in the logstash configs to convert this to numeric to enable range queries in kibana. 101 | 102 | # Credits 103 | https://www.docker.elastic.co/# 104 | 105 | https://github.com/patrickjennings/logstash-pfsense 106 | 107 | http://pfelk.3ilson.com/ 108 | 109 | https://github.com/siemonster/suricata 110 | 111 | https://github.com/elastic/stack-docker 112 | 113 | https://gist.github.com/elijahpaul/3d80030ac3e8138848b5#file-pfsense2-2-grok 114 | 115 | https://forum.netgate.com/topic/107735/elk-pfsense-2-3-working 116 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: '3' 3 | services: 4 | # The environment variable "TAG" is used throughout this file to 5 | # specify the version of the images to run. The default is set in the 6 | # '.env' file in this folder. It can be overridden with any normal 7 | # technique for setting environment variables, for example: 8 | # 9 | # TAG=6.0.0-beta1 docker-compose up 10 | # 11 | # REF: https://docs.docker.com/compose/compose-file/#variable-substitution 12 | # 13 | # Also be sure to set the ELASTIC_VERSION variable. For released versions, 14 | # ${TAG} and ${ELASTIC_VERSION} will be identical, but for pre-release 15 | # versions, ${TAG} might contain an extra build identifier, like 16 | # "6.0.0-beta1-3eab5b40", so a full invocation might look like: 17 | # 18 | # ELASTIC_VERSION=6.0.0-beta1 TAG=6.0.0-beta1-3eab5b40 docker-compose up 19 | # 20 | elasticsearch: 21 | image: docker.elastic.co/elasticsearch/elasticsearch:${TAG} 22 | container_name: elasticsearch 23 | environment: ['http.host=0.0.0.0', 'transport.host=127.0.0.1'] 24 | ports: ['127.0.0.1:9200:9200'] 25 | networks: ['stack'] 26 | volumes: 27 | - ./data/elastic/:/usr/share/elasticsearch/data/ 28 | 29 | kibana: 30 | image: docker.elastic.co/kibana/kibana:${TAG} 31 | container_name: kibana 32 | ports: ['127.0.0.1:5601:5601'] 33 | networks: ['stack'] 34 | depends_on: ['elasticsearch'] 35 | 36 | logstash: 37 | image: docker.elastic.co/logstash/logstash:${TAG} 38 | container_name: logstash 39 | # Provide a simple pipeline configuration for Logstash with a bind-mounted file. 40 | volumes: 41 | # - ./config/logstash/logstash.conf:/usr/share/logstash/pipeline/logstash.conf 42 | - ./config/logstash/pipeline/:/usr/share/logstash/pipeline/ 43 | - ./config/logstash/patterns/:/usr/share/logstash/patterns/ 44 | # - ./config/logstash/GeoLiteCity.dat:/usr/share/logstash/GeoLiteCity.dat 45 | ports: ['192.168.1.13:1514:1514/udp'] 46 | networks: ['stack'] 47 | depends_on: ['elasticsearch'] 48 | 49 | 50 | # auditbeat: 51 | # image: docker.elastic.co/beats/auditbeat:${TAG} 52 | # container_name: auditbeat 53 | # cap_add: ['AUDIT_CONTROL', 'AUDIT_READ'] 54 | # # Auditbeat must run in the main process namespace. 55 | # pid: host 56 | # networks: ['stack'] 57 | # depends_on: ['elasticsearch'] 58 | 59 | # filebeat: 60 | # image: docker.elastic.co/beats/filebeat:${TAG} 61 | # container_name: filebeat 62 | # # If the host system has logs at "/var/log", mount them at "/mnt/log" 63 | # # inside the container, where Filebeat can find them. 64 | # # volumes: ['/var/log:/mnt/log:ro'] 65 | # networks: ['stack'] 66 | # depends_on: ['elasticsearch', 'setup_filebeat'] 67 | 68 | # heartbeat: 69 | # image: docker.elastic.co/beats/heartbeat:${TAG} 70 | # container_name: heartbeat 71 | # networks: ['stack'] 72 | # depends_on: ['elasticsearch', 'setup_heartbeat'] 73 | 74 | # metricbeat: 75 | # image: docker.elastic.co/beats/metricbeat:${TAG} 76 | # container_name: metricbeat 77 | # # The commented sections below enable Metricbeat to monitor the Docker host, 78 | # # rather than the Metricbeat container. It's problematic with Docker for 79 | # # Windows, however, since "/proc", "/sys" etc. don't exist on Windows. 80 | # # The same likely applies to OSX (needs testing). 81 | # # volumes: 82 | # # - /proc:/hostfs/proc:ro 83 | # # - /sys/fs/cgroup:/hostfs/sys/fs/cgroup:ro 84 | # # - /:/hostfs:ro 85 | # networks: ['stack'] 86 | # depends_on: ['elasticsearch', 'setup_metricbeat'] 87 | 88 | # packetbeat: 89 | # image: docker.elastic.co/beats/packetbeat:${TAG} 90 | # container_name: packetbeat 91 | # # Packetbeat needs some elevated privileges to capture network traffic. 92 | # # We'll grant them with POSIX capabilities. 93 | # cap_add: ['NET_RAW', 'NET_ADMIN'] 94 | # # Use "host mode" networking to allow Packetbeat to capture traffic from 95 | # # the real network interface on the host, rather than being isolated to the 96 | # # container's virtual interface. 97 | # network_mode: host 98 | # # Since we did that, Packetbeat is not part of the "stack" Docker network 99 | # # that the other containers are connected to, and thus can't resolve the 100 | # # hostname "elasticsearch". Instead, we'll tell it to find Elasticsearch 101 | # # on "localhost", which is the Docker host machine in this context. 102 | # command: -e -E 'output.elasticsearch.hosts=["localhost:9200"]' 103 | # depends_on: ['elasticsearch'] 104 | 105 | # apm_server: 106 | # image: docker.elastic.co/apm/apm-server:${TAG} 107 | # container_name: apm_server 108 | # ports: ['127.0.0.1:8200:8200'] 109 | # networks: ['stack'] 110 | # depends_on: ['elasticsearch','setup_apm_server'] 111 | 112 | # # Run short-lived containers to set up the Beats. 113 | # setup_auditbeat: 114 | # image: docker.elastic.co/beats/auditbeat:${TAG} 115 | # container_name: setup_auditbeat 116 | # volumes: ['./scripts/setup-beat.sh:/usr/local/bin/setup-beat.sh:ro'] 117 | # # The script may have CR/LF line endings if using Docker for Windows, so 118 | # # remove them so that they won't confuse Bash. 119 | # command: ['/bin/bash', '-c', 'cat /usr/local/bin/setup-beat.sh | tr -d "\r" | bash -s auditbeat'] 120 | # networks: ['stack'] 121 | # depends_on: ['kibana'] 122 | 123 | # setup_filebeat: 124 | # image: docker.elastic.co/beats/filebeat:${TAG} 125 | # container_name: setup_filebeat 126 | # volumes: ['./scripts/setup-beat.sh:/usr/local/bin/setup-beat.sh:ro'] 127 | # command: ['/bin/bash', '-c', 'cat /usr/local/bin/setup-beat.sh | tr -d "\r" | bash -s filebeat'] 128 | # networks: ['stack'] 129 | # depends_on: ['kibana'] 130 | 131 | # setup_heartbeat: 132 | # image: docker.elastic.co/beats/heartbeat:${TAG} 133 | # container_name: setup_heartbeat 134 | # volumes: ['./scripts/setup-beat.sh:/usr/local/bin/setup-beat.sh:ro'] 135 | # command: ['/bin/bash', '-c', 'cat /usr/local/bin/setup-beat.sh | tr -d "\r" | bash -s heartbeat'] 136 | # networks: ['stack'] 137 | # depends_on: ['kibana'] 138 | 139 | # setup_metricbeat: 140 | # image: docker.elastic.co/beats/metricbeat:${TAG} 141 | # container_name: setup_metricbeat 142 | # volumes: ['./scripts/setup-beat.sh:/usr/local/bin/setup-beat.sh:ro'] 143 | # command: ['/bin/bash', '-c', 'cat /usr/local/bin/setup-beat.sh | tr -d "\r" | bash -s metricbeat'] 144 | # networks: ['stack'] 145 | # depends_on: ['kibana'] 146 | 147 | # setup_packetbeat: 148 | # image: docker.elastic.co/beats/packetbeat:${TAG} 149 | # container_name: setup_packetbeat 150 | # cap_add: ['NET_RAW', 'NET_ADMIN'] 151 | # volumes: ['./scripts/setup-beat.sh:/usr/local/bin/setup-beat.sh:ro'] 152 | # command: ['/bin/bash', '-c', 'cat /usr/local/bin/setup-beat.sh | tr -d "\r" | bash -s packetbeat'] 153 | # networks: ['stack'] 154 | # depends_on: ['kibana'] 155 | 156 | # setup_apm_server: 157 | # image: docker.elastic.co/apm/apm-server:${TAG} 158 | # container_name: setup_apm_server 159 | # volumes: ['./scripts/setup-beat.sh:/usr/local/bin/setup-beat.sh:ro'] 160 | # command: ['/bin/bash', '-c', 'cat /usr/local/bin/setup-beat.sh | tr -d "\r" | bash -s apm-server'] 161 | # networks: ['stack'] 162 | # depends_on: ['elasticsearch','kibana'] 163 | 164 | networks: {stack: {}} -------------------------------------------------------------------------------- /kibana/visualizations.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "_id": "33c9cd60-92c7-11e7-87a2-7940ffb808f9", 4 | "_type": "visualization", 5 | "_source": { 6 | "title": "Blocked Entree Metric", 7 | "visState": "{\"title\":\"Blocked Entree Metric\",\"type\":\"metric\",\"params\":{\"addTooltip\":true,\"addLegend\":true,\"type\":\"gauge\",\"gauge\":{\"verticalSplit\":false,\"autoExtend\":false,\"percentageMode\":false,\"gaugeType\":\"Arc\",\"gaugeStyle\":\"Full\",\"backStyle\":\"Full\",\"orientation\":\"vertical\",\"colorSchema\":\"Green to Red\",\"gaugeColorMode\":\"Labels\",\"useRange\":false,\"colorsRange\":[{\"from\":0,\"to\":200},{\"from\":200,\"to\":400},{\"from\":400,\"to\":600},{\"from\":600,\"to\":800},{\"from\":800,\"to\":1000},{\"from\":1000,\"to\":1200},{\"from\":1200,\"to\":1400}],\"invertColors\":false,\"labels\":{\"show\":true,\"color\":\"black\"},\"scale\":{\"show\":false,\"labels\":false,\"color\":\"#333\",\"width\":2},\"type\":\"meter\",\"style\":{\"fontSize\":60,\"bgColor\":false,\"labelColor\":true,\"subText\":\"Blocked Entrees\",\"bgFill\":\"\"},\"extendRange\":false}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}}],\"listeners\":{}}", 8 | "uiStateJSON": "{\"vis\":{\"defaultColors\":{\"0 - 200\":\"rgb(0,104,55)\",\"200 - 400\":\"rgb(76,176,93)\",\"400 - 600\":\"rgb(183,224,117)\",\"600 - 800\":\"rgb(255,255,190)\",\"800 - 1000\":\"rgb(253,191,111)\",\"1000 - 1200\":\"rgb(234,88,57)\",\"1200 - 1400\":\"rgb(165,0,38)\"},\"legendOpen\":true,\"colors\":{}}}", 9 | "description": "", 10 | "version": 1, 11 | "kibanaSavedObjectMeta": { 12 | "searchSourceJSON": "{\"index\":\"9aea6d00-7db4-11e8-b267-4d1688b0bab4\",\"query\":{\"query\":{\"match_all\":{}},\"language\":\"lucene\"},\"filter\":[{\"meta\":{\"index\":\"logstash-pfsense-*\",\"negate\":false,\"disabled\":false,\"alias\":\"Blocked\",\"type\":\"phrase\",\"key\":\"action\",\"value\":\"block\"},\"query\":{\"match\":{\"action\":{\"query\":\"block\",\"type\":\"phrase\"}}},\"$state\":{\"store\":\"appState\"}}]}" 13 | } 14 | } 15 | }, 16 | { 17 | "_id": "f636e740-92a2-11e7-b4f8-6947ec97a76c", 18 | "_type": "visualization", 19 | "_source": { 20 | "title": "GeoIP Tile Map", 21 | "visState": "{\"aggs\":[{\"enabled\":true,\"id\":\"1\",\"params\":{},\"schema\":\"metric\",\"type\":\"count\"},{\"enabled\":true,\"id\":\"2\",\"params\":{\"autoPrecision\":true,\"field\":\"geoip.location\",\"precision\":2,\"useGeocentroid\":true},\"schema\":\"segment\",\"type\":\"geohash_grid\"}],\"listeners\":{},\"params\":{\"addTooltip\":true,\"heatBlur\":15,\"heatMaxZoom\":0,\"heatMinOpacity\":0.1,\"heatRadius\":25,\"isDesaturated\":true,\"legendPosition\":\"bottomright\",\"mapCenter\":[0,0],\"mapType\":\"Scaled Circle Markers\",\"mapZoom\":2,\"wms\":{\"enabled\":false,\"options\":{\"attribution\":\"Maps provided by USGS\",\"format\":\"image/png\",\"layers\":\"0\",\"styles\":\"\",\"transparent\":true,\"version\":\"1.3.0\"},\"url\":\"https://basemap.nationalmap.gov/arcgis/services/USGSTopo/MapServer/WMSServer\"}},\"title\":\"GeoIP Tile Map\",\"type\":\"tile_map\"}", 22 | "uiStateJSON": "{\"mapCenter\":[0,-0.087890625],\"mapZoom\":3}", 23 | "description": "", 24 | "version": 1, 25 | "kibanaSavedObjectMeta": { 26 | "searchSourceJSON": "{\"index\":\"9aea6d00-7db4-11e8-b267-4d1688b0bab4\",\"query\":{\"query\":{\"match_all\":{}},\"language\":\"lucene\"},\"filter\":[]}" 27 | } 28 | } 29 | }, 30 | { 31 | "_id": "48e91180-7e1f-11e8-b267-4d1688b0bab4", 32 | "_type": "visualization", 33 | "_source": { 34 | "title": "Suricata Alert Groups", 35 | "visState": "{\"aggs\":[{\"enabled\":true,\"id\":\"1\",\"params\":{},\"schema\":\"metric\",\"type\":\"count\"},{\"enabled\":true,\"id\":\"2\",\"params\":{\"customLabel\":\"Alert Group\",\"field\":\"alert.signature.keyword\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"size\":25},\"schema\":\"segment\",\"type\":\"terms\"},{\"enabled\":true,\"id\":\"3\",\"params\":{\"customLabel\":\"Unique IPs by Port\",\"field\":\"dest_port.keyword\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"order\":\"desc\",\"orderAgg\":{\"enabled\":true,\"id\":\"3-orderAgg\",\"params\":{\"field\":\"src_ip.keyword\"},\"schema\":{\"aggFilter\":[\"!top_hits\",\"!percentiles\",\"!median\",\"!std_dev\",\"!derivative\",\"!moving_avg\",\"!serial_diff\",\"!cumulative_sum\",\"!avg_bucket\",\"!max_bucket\",\"!min_bucket\",\"!sum_bucket\"],\"deprecate\":false,\"editor\":false,\"group\":\"none\",\"hideCustomLabel\":true,\"max\":null,\"min\":0,\"name\":\"orderAgg\",\"params\":[],\"title\":\"Order Agg\"},\"type\":\"cardinality\"},\"orderBy\":\"custom\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"size\":100},\"schema\":\"group\",\"type\":\"terms\"}],\"params\":{\"addLegend\":true,\"addTimeMarker\":false,\"addTooltip\":true,\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"labels\":{\"show\":true,\"truncate\":100},\"position\":\"bottom\",\"scale\":{\"type\":\"linear\"},\"show\":true,\"style\":{},\"title\":{},\"type\":\"category\"}],\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"legendPosition\":\"right\",\"seriesParams\":[{\"data\":{\"id\":\"1\",\"label\":\"Count\"},\"drawLinesBetweenPoints\":true,\"mode\":\"stacked\",\"show\":\"true\",\"showCircles\":true,\"type\":\"histogram\",\"valueAxis\":\"ValueAxis-1\"}],\"times\":[],\"type\":\"histogram\",\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"labels\":{\"filter\":false,\"rotate\":0,\"show\":true,\"truncate\":100},\"name\":\"LeftAxis-1\",\"position\":\"left\",\"scale\":{\"mode\":\"normal\",\"type\":\"linear\"},\"show\":true,\"style\":{},\"title\":{\"text\":\"Count\"},\"type\":\"value\"}]},\"title\":\"Suricata Alert Groups\",\"type\":\"histogram\"}", 36 | "uiStateJSON": "{}", 37 | "description": "", 38 | "version": 1, 39 | "kibanaSavedObjectMeta": { 40 | "searchSourceJSON": "{\"index\":\"9aea6d00-7db4-11e8-b267-4d1688b0bab4\",\"filter\":[{\"query\":{\"wildcard\":{\"prog.keyword\":\"suricata*\"}},\"meta\":{\"negate\":false,\"index\":\"9aea6d00-7db4-11e8-b267-4d1688b0bab4\",\"disabled\":false,\"alias\":null,\"type\":\"custom\",\"key\":\"query\",\"value\":\"{\\\"wildcard\\\":{\\\"prog.keyword\\\":\\\"suricata*\\\"}}\"},\"$state\":{\"store\":\"appState\"}}],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}" 41 | } 42 | } 43 | }, 44 | { 45 | "_id": "b8004160-7e2e-11e8-b267-4d1688b0bab4", 46 | "_type": "visualization", 47 | "_source": { 48 | "title": "Suricata Attack Methods", 49 | "visState": "{\"title\":\"Suricata Attack Methods\",\"type\":\"tile_map\",\"params\":{\"mapType\":\"Scaled Circle Markers\",\"isDesaturated\":true,\"addTooltip\":true,\"heatClusterSize\":1.5,\"legendPosition\":\"bottomright\",\"mapZoom\":2,\"mapCenter\":[0,0],\"wms\":{\"enabled\":false,\"options\":{\"format\":\"image/png\",\"transparent\":true},\"baseLayersAreLoaded\":{},\"tmsLayers\":[{\"id\":\"road_map\",\"url\":\"https://tiles.maps.elastic.co/v2/default/{z}/{x}/{y}.png?elastic_tile_service_tos=agree&my_app_name=kibana&my_app_version=6.3.0&license=347efadd-d40b-4eaf-912f-e9dd66882e1d\",\"minZoom\":0,\"maxZoom\":18,\"attribution\":\"

© OpenStreetMap contributors | Elastic Maps Service

\",\"subdomains\":[]}],\"selectedTmsLayer\":{\"id\":\"road_map\",\"url\":\"https://tiles.maps.elastic.co/v2/default/{z}/{x}/{y}.png?elastic_tile_service_tos=agree&my_app_name=kibana&my_app_version=6.3.0&license=347efadd-d40b-4eaf-912f-e9dd66882e1d\",\"minZoom\":0,\"maxZoom\":18,\"attribution\":\"

© OpenStreetMap contributors | Elastic Maps Service

\",\"subdomains\":[]}}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"cardinality\",\"schema\":\"metric\",\"params\":{\"field\":\"alert.signature.keyword\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"geohash_grid\",\"schema\":\"segment\",\"params\":{\"field\":\"geoip.location\",\"autoPrecision\":true,\"isFilteredByCollar\":true,\"useGeocentroid\":true,\"precision\":2}}]}", 50 | "uiStateJSON": "{}", 51 | "description": "", 52 | "version": 1, 53 | "kibanaSavedObjectMeta": { 54 | "searchSourceJSON": "{\"index\":\"9aea6d00-7db4-11e8-b267-4d1688b0bab4\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}" 55 | } 56 | } 57 | }, 58 | { 59 | "_id": "8b1898c0-7e18-11e8-b267-4d1688b0bab4", 60 | "_type": "visualization", 61 | "_source": { 62 | "title": "Suricata Alert IPs", 63 | "visState": "{\"title\":\"Suricata Alert IPs\",\"type\":\"histogram\",\"params\":{\"type\":\"histogram\",\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"truncate\":100},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Count\"}}],\"seriesParams\":[{\"show\":\"true\",\"type\":\"histogram\",\"mode\":\"stacked\",\"data\":{\"label\":\"Count\",\"id\":\"1\"},\"valueAxis\":\"ValueAxis-1\",\"drawLinesBetweenPoints\":true,\"showCircles\":true}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"src_ip.keyword\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"size\":25,\"order\":\"desc\",\"orderBy\":\"1\"}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"dest_port.keyword\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"size\":100,\"order\":\"desc\",\"orderBy\":\"1\"}}]}", 64 | "uiStateJSON": "{}", 65 | "description": "", 66 | "version": 1, 67 | "kibanaSavedObjectMeta": { 68 | "searchSourceJSON": "{\"index\":\"9aea6d00-7db4-11e8-b267-4d1688b0bab4\",\"filter\":[{\"query\":{\"wildcard\":{\"prog.keyword\":\"suricata*\"}},\"meta\":{\"negate\":false,\"index\":\"9aea6d00-7db4-11e8-b267-4d1688b0bab4\",\"disabled\":false,\"alias\":null,\"type\":\"custom\",\"key\":\"query\",\"value\":\"{\\\"wildcard\\\":{\\\"prog.keyword\\\":\\\"suricata*\\\"}}\"},\"$state\":{\"store\":\"appState\"}}],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}" 69 | } 70 | } 71 | }, 72 | { 73 | "_id": "135aae00-7e30-11e8-b267-4d1688b0bab4", 74 | "_type": "visualization", 75 | "_source": { 76 | "title": "Suricata Attack Count Map", 77 | "visState": "{\"title\":\"Suricata Attack Count Map\",\"type\":\"region_map\",\"params\":{\"addTooltip\":true,\"colorSchema\":\"Yellow to Red\",\"isDisplayWarning\":true,\"legendPosition\":\"bottomright\",\"mapCenter\":[0,0],\"mapZoom\":2,\"outlineWeight\":1,\"selectedJoinField\":{\"description\":\"Two letter abbreviation\",\"name\":\"iso2\"},\"selectedLayer\":{\"attribution\":\"

Made with NaturalEarth | Elastic Maps Service

\",\"created_at\":\"2017-04-26T17:12:15.978370\",\"fields\":[{\"description\":\"Two letter abbreviation\",\"name\":\"iso2\"},{\"description\":\"Country name\",\"name\":\"name\"},{\"description\":\"Three letter abbreviation\",\"name\":\"iso3\"}],\"format\":{\"type\":\"geojson\"},\"id\":5659313586569216,\"layerId\":\"elastic_maps_service.World Countries\",\"name\":\"World Countries\",\"tags\":[],\"url\":\"https://vector.maps.elastic.co/blob/5659313586569216?elastic_tile_service_tos=agree&my_app_version=6.3.0&license=347efadd-d40b-4eaf-912f-e9dd66882e1d\",\"weight\":1},\"showAllShapes\":true,\"wms\":{\"baseLayersAreLoaded\":{},\"enabled\":false,\"options\":{\"format\":\"image/png\",\"transparent\":true},\"selectedTmsLayer\":{\"attribution\":\"

© OpenStreetMap contributors | Elastic Maps Service

\",\"id\":\"road_map\",\"maxZoom\":18,\"minZoom\":0,\"subdomains\":[],\"url\":\"https://tiles.maps.elastic.co/v2/default/{z}/{x}/{y}.png?elastic_tile_service_tos=agree&my_app_name=kibana&my_app_version=6.3.0&license=347efadd-d40b-4eaf-912f-e9dd66882e1d\"},\"tmsLayers\":[{\"attribution\":\"

© OpenStreetMap contributors | Elastic Maps Service

\",\"id\":\"road_map\",\"maxZoom\":18,\"minZoom\":0,\"subdomains\":[],\"url\":\"https://tiles.maps.elastic.co/v2/default/{z}/{x}/{y}.png?elastic_tile_service_tos=agree&my_app_name=kibana&my_app_version=6.3.0&license=347efadd-d40b-4eaf-912f-e9dd66882e1d\"}]}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"geoip.country_code3.keyword\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\"}}]}", 78 | "uiStateJSON": "{}", 79 | "description": "", 80 | "version": 1, 81 | "kibanaSavedObjectMeta": { 82 | "searchSourceJSON": "{\"index\":\"9aea6d00-7db4-11e8-b267-4d1688b0bab4\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}" 83 | } 84 | } 85 | }, 86 | { 87 | "_id": "fcdc1200-7e29-11e8-b267-4d1688b0bab4", 88 | "_type": "visualization", 89 | "_source": { 90 | "title": "GeoIP Known Threats", 91 | "visState": "{\"title\":\"GeoIP Known Threats\",\"type\":\"tile_map\",\"params\":{\"mapType\":\"Scaled Circle Markers\",\"isDesaturated\":true,\"addTooltip\":true,\"heatClusterSize\":1.5,\"legendPosition\":\"bottomright\",\"mapZoom\":2,\"mapCenter\":[0,0],\"wms\":{\"enabled\":false,\"options\":{\"format\":\"image/png\",\"transparent\":true},\"baseLayersAreLoaded\":{},\"tmsLayers\":[{\"id\":\"road_map\",\"url\":\"https://tiles.maps.elastic.co/v2/default/{z}/{x}/{y}.png?elastic_tile_service_tos=agree&my_app_name=kibana&my_app_version=6.3.0&license=347efadd-d40b-4eaf-912f-e9dd66882e1d\",\"minZoom\":0,\"maxZoom\":18,\"attribution\":\"

© OpenStreetMap contributors | Elastic Maps Service

\",\"subdomains\":[]}],\"selectedTmsLayer\":{\"id\":\"road_map\",\"url\":\"https://tiles.maps.elastic.co/v2/default/{z}/{x}/{y}.png?elastic_tile_service_tos=agree&my_app_name=kibana&my_app_version=6.3.0&license=347efadd-d40b-4eaf-912f-e9dd66882e1d\",\"minZoom\":0,\"maxZoom\":18,\"attribution\":\"

© OpenStreetMap contributors | Elastic Maps Service

\",\"subdomains\":[]}}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"geohash_grid\",\"schema\":\"segment\",\"params\":{\"field\":\"geoip.location\",\"autoPrecision\":true,\"isFilteredByCollar\":true,\"useGeocentroid\":true,\"precision\":2}}]}", 92 | "uiStateJSON": "{\"mapZoom\":3,\"mapCenter\":[23.07973176244989,-10.195312500000002]}", 93 | "description": "", 94 | "version": 1, 95 | "kibanaSavedObjectMeta": { 96 | "searchSourceJSON": "{\"index\":\"9aea6d00-7db4-11e8-b267-4d1688b0bab4\",\"filter\":[{\"query\":{\"wildcard\":{\"prog.keyword\":\"suricata*\"}},\"meta\":{\"index\":\"9aea6d00-7db4-11e8-b267-4d1688b0bab4\",\"disabled\":false,\"alias\":null,\"type\":\"custom\",\"key\":\"query\",\"value\":\"{\\\"wildcard\\\":{\\\"prog.keyword\\\":\\\"suricata*\\\"}}\",\"negate\":false},\"$state\":{\"store\":\"appState\"}}],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}" 97 | } 98 | } 99 | }, 100 | { 101 | "_id": "7a16cea0-7e3d-11e8-a400-fb1b13f7ba25", 102 | "_type": "visualization", 103 | "_source": { 104 | "title": "Suricata Alerted Entree Metric", 105 | "visState": "{\"title\":\"Suricata Alerted Entree Metric\",\"type\":\"metric\",\"params\":{\"addTooltip\":true,\"addLegend\":true,\"type\":\"gauge\",\"gauge\":{\"verticalSplit\":false,\"autoExtend\":false,\"percentageMode\":false,\"gaugeType\":\"Arc\",\"gaugeStyle\":\"Full\",\"backStyle\":\"Full\",\"orientation\":\"vertical\",\"colorSchema\":\"Green to Red\",\"gaugeColorMode\":\"Labels\",\"useRange\":false,\"colorsRange\":[{\"from\":0,\"to\":200},{\"from\":200,\"to\":400},{\"from\":400,\"to\":600},{\"from\":600,\"to\":800},{\"from\":800,\"to\":1000},{\"from\":1000,\"to\":1200},{\"from\":1200,\"to\":1400}],\"invertColors\":false,\"labels\":{\"show\":true,\"color\":\"black\"},\"scale\":{\"show\":false,\"labels\":false,\"color\":\"#333\",\"width\":2},\"type\":\"meter\",\"style\":{\"fontSize\":60,\"bgColor\":false,\"labelColor\":true,\"subText\":\"Blocked Entrees\",\"bgFill\":\"\"},\"extendRange\":false},\"metric\":{\"percentageMode\":false,\"useRanges\":false,\"colorSchema\":\"Green to Red\",\"metricColorMode\":\"None\",\"colorsRange\":[{\"from\":0,\"to\":10000}],\"labels\":{\"show\":true},\"invertColors\":false,\"style\":{\"bgFill\":\"#000\",\"bgColor\":false,\"labelColor\":false,\"subText\":\"\",\"fontSize\":60}}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}}]}", 106 | "uiStateJSON": "{\"vis\":{\"defaultColors\":{\"0 - 200\":\"rgb(0,104,55)\",\"200 - 400\":\"rgb(76,176,93)\",\"400 - 600\":\"rgb(183,224,117)\",\"600 - 800\":\"rgb(255,255,190)\",\"800 - 1000\":\"rgb(253,191,111)\",\"1000 - 1200\":\"rgb(234,88,57)\",\"1200 - 1400\":\"rgb(165,0,38)\"},\"legendOpen\":true,\"colors\":{}}}", 107 | "description": "", 108 | "version": 1, 109 | "kibanaSavedObjectMeta": { 110 | "searchSourceJSON": "{\"index\":\"9aea6d00-7db4-11e8-b267-4d1688b0bab4\",\"query\":{\"query\":{\"match_all\":{}},\"language\":\"lucene\"},\"filter\":[{\"query\":{\"wildcard\":{\"prog.keyword\":\"suricata*\"}},\"meta\":{\"index\":\"9aea6d00-7db4-11e8-b267-4d1688b0bab4\",\"disabled\":false,\"alias\":null,\"type\":\"custom\",\"key\":\"query\",\"value\":\"{\\\"wildcard\\\":{\\\"prog.keyword\\\":\\\"suricata*\\\"}}\",\"negate\":false},\"$state\":{\"store\":\"appState\"}}]}" 111 | } 112 | } 113 | }, 114 | { 115 | "_id": "ed689730-9379-11e7-851b-4be14ad14ed6", 116 | "_type": "visualization", 117 | "_source": { 118 | "title": "Blocked IPs & Ports", 119 | "visState": "{\"title\":\"Blocked IPs & Ports\",\"type\":\"histogram\",\"params\":{\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"truncate\":100},\"title\":{\"text\":\"Blocked IP\"}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Count\"}}],\"seriesParams\":[{\"show\":\"true\",\"type\":\"histogram\",\"mode\":\"stacked\",\"data\":{\"label\":\"Count\",\"id\":\"1\"},\"valueAxis\":\"ValueAxis-1\",\"drawLinesBetweenPoints\":true,\"showCircles\":true}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false,\"type\":\"histogram\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"src_ip.keyword\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"size\":25,\"order\":\"desc\",\"orderBy\":\"1\",\"customLabel\":\"Blocked IP\"}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"dest_port.keyword\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"size\":100,\"order\":\"desc\",\"orderBy\":\"1\",\"customLabel\":\"Port\"}}]}", 120 | "uiStateJSON": "{}", 121 | "description": "", 122 | "version": 1, 123 | "kibanaSavedObjectMeta": { 124 | "searchSourceJSON": "{\"index\":\"9aea6d00-7db4-11e8-b267-4d1688b0bab4\",\"query\":{\"query\":{\"query_string\":{\"analyze_wildcard\":true,\"query\":\"action: block\",\"default_field\":\"*\"}},\"language\":\"lucene\"},\"filter\":[{\"meta\":{\"index\":\"9aea6d00-7db4-11e8-b267-4d1688b0bab4\",\"negate\":true,\"disabled\":false,\"alias\":null,\"type\":\"phrase\",\"key\":\"iface\",\"value\":\"igb1\",\"params\":{\"query\":\"igb1\",\"type\":\"phrase\"}},\"query\":{\"match\":{\"iface\":{\"query\":\"igb1\",\"type\":\"phrase\"}}},\"$state\":{\"store\":\"appState\"}}]}" 125 | } 126 | } 127 | }, 128 | { 129 | "_id": "e5b1e0d0-7e30-11e8-b267-4d1688b0bab4", 130 | "_type": "visualization", 131 | "_source": { 132 | "title": "Suricata Alert Group Size", 133 | "visState": "{\"title\":\"Suricata Alert Group Size\",\"type\":\"pie\",\"params\":{\"addLegend\":true,\"addTooltip\":true,\"isDonut\":true,\"labels\":{\"last_level\":true,\"show\":false,\"truncate\":100,\"values\":true},\"legendPosition\":\"right\",\"type\":\"pie\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"cardinality\",\"schema\":\"metric\",\"params\":{\"field\":\"src_ip.keyword\"}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"alert.signature.keyword\",\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"size\":15,\"order\":\"desc\",\"orderBy\":\"1\"}},{\"id\":\"4\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"src_ip.keyword\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\"}}]}", 134 | "uiStateJSON": "{}", 135 | "description": "", 136 | "version": 1, 137 | "kibanaSavedObjectMeta": { 138 | "searchSourceJSON": "{\"index\":\"9aea6d00-7db4-11e8-b267-4d1688b0bab4\",\"filter\":[{\"$state\":{\"store\":\"appState\"},\"meta\":{\"alias\":null,\"disabled\":false,\"index\":\"9aea6d00-7db4-11e8-b267-4d1688b0bab4\",\"key\":\"query\",\"negate\":false,\"type\":\"custom\",\"value\":\"{\\\"wildcard\\\":{\\\"prog.keyword\\\":\\\"suricata*\\\"}}\"},\"query\":{\"wildcard\":{\"prog.keyword\":\"suricata*\"}}}],\"query\":{\"language\":\"lucene\",\"query\":\"\"}}" 139 | } 140 | } 141 | }, 142 | { 143 | "_id": "b3c31a50-92c5-11e7-87a2-7940ffb808f9", 144 | "_type": "visualization", 145 | "_source": { 146 | "title": "Common Destination Ports", 147 | "visState": "{\"title\":\"Common Destination Ports\",\"type\":\"pie\",\"params\":{\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"type\":\"pie\",\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"dest_port.keyword\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"size\":20,\"order\":\"desc\",\"orderBy\":\"1\",\"customLabel\":\"Destination Port\"}}]}", 148 | "uiStateJSON": "{\"vis\":{\"legendOpen\":true}}", 149 | "description": "", 150 | "version": 1, 151 | "kibanaSavedObjectMeta": { 152 | "searchSourceJSON": "{\"index\":\"9aea6d00-7db4-11e8-b267-4d1688b0bab4\",\"query\":{\"language\":\"lucene\",\"query\":{\"match_all\":{}}},\"filter\":[{\"$state\":{\"store\":\"appState\"},\"meta\":{\"alias\":null,\"disabled\":false,\"index\":\"9aea6d00-7db4-11e8-b267-4d1688b0bab4\",\"key\":\"iface\",\"negate\":true,\"params\":{\"query\":\"igb1\",\"type\":\"phrase\"},\"type\":\"phrase\",\"value\":\"igb1\"},\"query\":{\"match\":{\"iface\":{\"query\":\"igb1\",\"type\":\"phrase\"}}}}]}" 153 | } 154 | } 155 | }, 156 | { 157 | "_id": "df49d9e0-7e2c-11e8-b267-4d1688b0bab4", 158 | "_type": "visualization", 159 | "_source": { 160 | "title": "Suricata Country Unique Attacks", 161 | "visState": "{\"title\":\"Suricata Country Unique Attacks\",\"type\":\"pie\",\"params\":{\"addLegend\":true,\"addTooltip\":true,\"isDonut\":true,\"labels\":{\"last_level\":true,\"show\":false,\"truncate\":100,\"values\":true},\"legendPosition\":\"right\",\"type\":\"pie\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"cardinality\",\"schema\":\"metric\",\"params\":{\"field\":\"src_ip.keyword\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"geoip.country_name.keyword\",\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"size\":20,\"order\":\"desc\",\"orderBy\":\"_term\"}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"alert.signature.keyword\",\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"size\":20,\"order\":\"desc\",\"orderBy\":\"1\"}}]}", 162 | "uiStateJSON": "{}", 163 | "description": "", 164 | "version": 1, 165 | "kibanaSavedObjectMeta": { 166 | "searchSourceJSON": "{\"index\":\"9aea6d00-7db4-11e8-b267-4d1688b0bab4\",\"filter\":[{\"query\":{\"wildcard\":{\"prog.keyword\":\"suricata*\"}},\"meta\":{\"index\":\"9aea6d00-7db4-11e8-b267-4d1688b0bab4\",\"disabled\":false,\"alias\":null,\"type\":\"custom\",\"key\":\"query\",\"value\":\"{\\\"wildcard\\\":{\\\"prog.keyword\\\":\\\"suricata*\\\"}}\",\"negate\":false},\"$state\":{\"store\":\"appState\"}}],\"query\":{\"language\":\"lucene\",\"query\":\"\"}}" 167 | } 168 | } 169 | } 170 | ] --------------------------------------------------------------------------------