From 7898cb17e91e8d841cfc737a1a2917e5aefea90c Mon Sep 17 00:00:00 2001 From: surtur Date: Mon, 17 May 2021 04:47:37 +0200 Subject: [PATCH] chore: add ansible roles for defender playbook --- .gitmodules | 6 + ansible.cfg | 13 + playbooks/defender.yml | 12 + playbooks/host_vars/h_defender.yml | 20 ++ roles/ansible-fprobe | 1 + roles/ansible-gobgp | 1 + roles/fastnetmon/README.md | 9 + roles/fastnetmon/defaults/main.yml | 22 ++ roles/fastnetmon/tasks/main.yml | 39 +++ roles/fastnetmon/templates/fastnetmon.conf.j2 | 320 ++++++++++++++++++ roles/fastnetmon/vars/main.yml | 1 + roles/ndpi/README.md | 9 + roles/ndpi/defaults/main.yml | 3 + roles/ndpi/tasks/main.yml | 27 ++ roles/ndpi/vars/main.yml | 1 + roles/waitpls/README.md | 9 + roles/waitpls/defaults/main.yml | 1 + roles/waitpls/tasks/main.yml | 8 + roles/waitpls/vars/main.yml | 1 + vms/main.tf | 26 +- vms/terraform.tfvars | 1 + 21 files changed, 526 insertions(+), 4 deletions(-) create mode 100644 .gitmodules create mode 100644 ansible.cfg create mode 100644 playbooks/defender.yml create mode 100644 playbooks/host_vars/h_defender.yml create mode 160000 roles/ansible-fprobe create mode 160000 roles/ansible-gobgp create mode 100644 roles/fastnetmon/README.md create mode 100644 roles/fastnetmon/defaults/main.yml create mode 100644 roles/fastnetmon/tasks/main.yml create mode 100644 roles/fastnetmon/templates/fastnetmon.conf.j2 create mode 100644 roles/fastnetmon/vars/main.yml create mode 100644 roles/ndpi/README.md create mode 100644 roles/ndpi/defaults/main.yml create mode 100644 roles/ndpi/tasks/main.yml create mode 100644 roles/ndpi/vars/main.yml create mode 100644 roles/waitpls/README.md create mode 100644 roles/waitpls/defaults/main.yml create mode 100644 roles/waitpls/tasks/main.yml create mode 100644 roles/waitpls/vars/main.yml diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..c38d68d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "roles/ansible-gobgp"] + path = roles/ansible-gobgp + url = https://git.dotya.ml/mirre-bt/ansible-gobgp +[submodule "roles/ansible-fprobe"] + path = roles/ansible-fprobe + url = https://git.dotya.ml/mirre-bt/ansible-fprobe diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..8ebed80 --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,13 @@ +[defaults] +inventory = hosts +remote_tmp = $HOME/.ansible/tmp +remote_user = root +nocows = 1 +roles_path = roles +retry_files_enabled = False +max_diff_size = 250000 + +[ssh_connection] +pipelining = True +scp_if_ssh = True +retries = 5 diff --git a/playbooks/defender.yml b/playbooks/defender.yml new file mode 100644 index 0000000..47e2d1c --- /dev/null +++ b/playbooks/defender.yml @@ -0,0 +1,12 @@ +--- +- hosts: defender + user: ansible + become: true + become_user: root + become_method: sudo + roles: + - { role: waitpls } + - { role: ansible-gobgp } + - { role: ndpi } + - { role: fastnetmon } + - { role: ansible-fprobe } diff --git a/playbooks/host_vars/h_defender.yml b/playbooks/host_vars/h_defender.yml new file mode 100644 index 0000000..5b62bc4 --- /dev/null +++ b/playbooks/host_vars/h_defender.yml @@ -0,0 +1,20 @@ +GOBGP_CONF: + global: + config: + as: 65000 + router-id: 10.16.6.1 + port: 179 + neighbors: + - config: + neighbor-address: 10.16.6.2 + peer-as: 65001 + transport: + config: + remote-port: "179" + add-paths: + config: + send-max: "8" + receive: false + afi-safis: + - config: + afi-safi-name: ipv4-unicast diff --git a/roles/ansible-fprobe b/roles/ansible-fprobe new file mode 160000 index 0000000..c3d75c8 --- /dev/null +++ b/roles/ansible-fprobe @@ -0,0 +1 @@ +Subproject commit c3d75c837813735a708625949b387b1216ae215d diff --git a/roles/ansible-gobgp b/roles/ansible-gobgp new file mode 160000 index 0000000..d39074a --- /dev/null +++ b/roles/ansible-gobgp @@ -0,0 +1 @@ +Subproject commit d39074a8e65f1d2b5bce155b257ab85abcfde302 diff --git a/roles/fastnetmon/README.md b/roles/fastnetmon/README.md new file mode 100644 index 0000000..45f2433 --- /dev/null +++ b/roles/fastnetmon/README.md @@ -0,0 +1,9 @@ +# ansible-fastnetmon +this role builds fastnetmon from source on a fedora machine + +## License +GPLv3 + +## Author +wanderer@git.dotya.ml + diff --git a/roles/fastnetmon/defaults/main.yml b/roles/fastnetmon/defaults/main.yml new file mode 100644 index 0000000..87297f4 --- /dev/null +++ b/roles/fastnetmon/defaults/main.yml @@ -0,0 +1,22 @@ +--- +fastnetmon_clone_dir: /tmp/fastnetmon-ng +netflow_on: on +netflow_port: 2055 + +ban_time: 1900 + +ban_for_pps: on +ban_for_bandwidth: on +ban_for_flows: off + +threshold_pps: 20000 +threshold_mbps: 1000 +threshold_flows: 3500 + +threshold_tcp_pps: 100000 +threshold_udp_pps: 100000 +threshold_icmp_pps: 100000 + +ban_for_tcp_pps: on +ban_for_udp_pps: on +ban_for_icmp_pps: on diff --git a/roles/fastnetmon/tasks/main.yml b/roles/fastnetmon/tasks/main.yml new file mode 100644 index 0000000..d444d82 --- /dev/null +++ b/roles/fastnetmon/tasks/main.yml @@ -0,0 +1,39 @@ +--- +- firewalld: + port: "{{netflow_port}}/udp" + permanent: true + state: enabled + +- name: check if fastnetmon dir exists + stat: + path: "{{fastnetmon_clone_dir}}" + register: dir_present + +- name: get fastnetmon sources + shell: + cmd: git clone https://git.dotya.ml/wanderer/fastnetmon-ng {{fastnetmon_clone_dir}} + when: not dir_present.stat.exists + +- name: build and install fastnetmon + shell: + cmd: + cd {{fastnetmon_clone_dir}}/src; + git checkout fresh-ndpi; + git apply patches/dev-ndpi.patch; + cmake -D"USE_NEW_ATOMIC_BUILTINS=ON" -D"ENABLE_AFPACKET_SUPPORT=ON" -D"ENABLE_GOBGP_SUPPORT=ON" -D"BUILD_PLUGIN_RUNNER=ON" -D"BUILD_TESTS=OFF" -DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS -Wall -Wextra" . && + make clean fastnetmon all install + chdir: "{{fastnetmon_clone_dir}}/src" + +- name: run ldconfig + shell: + cmd: ldconfig + +- name: copy config + template: + src: fastnetmon.conf.j2 + dest: /etc/fastnetmon.conf + mode: '0755' + backup: yes + ignore_errors: true + + diff --git a/roles/fastnetmon/templates/fastnetmon.conf.j2 b/roles/fastnetmon/templates/fastnetmon.conf.j2 new file mode 100644 index 0000000..91037c1 --- /dev/null +++ b/roles/fastnetmon/templates/fastnetmon.conf.j2 @@ -0,0 +1,320 @@ +{{ ansible_managed | comment }} +### +### Main configuration params +### + +### Logging configuration + +# enable this option if you want to send logs to local syslog facility +logging:local_syslog_logging = off + +# enable this option if you want to send logs to a remote syslog server via UDP +logging:remote_syslog_logging = off + +# specify a custom server and port for remote logging +logging:remote_syslog_server = 10.10.10.10 +logging:remote_syslog_port = 514 + +# Enable/Disable any actions in case of attack +enable_ban = on + +# Enable ban for IPv6 +enable_ban_ipv6 = on + +# disable processing for certain direction of traffic +process_incoming_traffic = on +process_outgoing_traffic = on + +# How many packets will be collected from attack traffic +ban_details_records_count = 50 + +# How long (in seconds) we should keep an IP in blocked state +# If you set 0 here it completely disables unban capability +ban_time = {{ ban_time }} + +# Check if the attack is still active, before triggering an unban callback with this option +# If the attack is still active, check each run of the unban watchdog +unban_only_if_attack_finished = on + +# enable per subnet speed meters +# For each subnet, list track speed in bps and pps for both directions +enable_subnet_counters = off + +# list of all your networks in CIDR format +networks_list_path = /etc/networks_list + +# list networks in CIDR format which will be not monitored for attacks +white_list_path = /etc/networks_whitelist + +# redraw period for client's screen +check_period = 1 + +# Connection tracking is very useful for attack detection because it provides huge amounts of information, +# but it's very CPU intensive and not recommended in big networks +enable_connection_tracking = on + +# Different approaches to attack detection +ban_for_pps = {{ ban_for_pps }} +ban_for_bandwidth = {{ ban_for_bandwidth }} +ban_for_flows = {{ ban_for_flows }} + +# Limits for Dos/DDoS attacks +threshold_pps = {{ threshold_pps }} +threshold_mbps = {{ threshold_mbps }} +threshold_flows = {{ threshold_flows }} + +# Per protocol attack thresholds +# We don't implement per protocol flow limits +# These limits should be smaller than global pps/mbps limits + +threshold_tcp_mbps = 100000 +threshold_udp_mbps = 100000 +threshold_icmp_mbps = 100000 + +threshold_tcp_pps = {{ threshold_tcp_pps }} +threshold_udp_pps = {{ threshold_udp_pps }} +threshold_icmp_pps = {{ threshold_icmp_pps }} + +ban_for_tcp_bandwidth = off +ban_for_udp_bandwidth = off +ban_for_icmp_bandwidth = off + +ban_for_tcp_pps = {{ ban_for_tcp_pps }} +ban_for_udp_pps = {{ ban_for_udp_pps }} +ban_for_icmp_pps = {{ ban_for_icmp_pps }} + +### +### Traffic capture methods +### + +# PF_RING traffic capture, fast enough but the wirespeed version needs a paid license +mirror = off + +# Port mirroring sample rate +pfring_sampling_ratio = 1 + +# Netmap traffic capture (very fast but needs patched drivers) +mirror_netmap = off + +# AF_PACKET capture engine +# Please use it only with modern Linux kernels (3.6 and more) +# And please install birq for irq ditribution over cores +mirror_afpacket = off + +# You can use this option to multiply all incoming traffc by this value +# It may be useful for sampled mirror ports +mirror_af_packet_custom_sampling_rate = 1 + +# AF_PACKET fanout mode mode, http://man7.org/linux/man-pages/man7/packet.7.html +# Available modes: cpu, lb, hash, random, rollover, queue_mapping +mirror_af_packet_fanout_mode = cpu + +# This option should be enabled if you are using Juniper with mirroring of the first X bytesof packet: maximum-packet-length 110; +af_packet_read_packet_length_from_ip_header = off + +# Port mirroring sampling ratio +netmap_sampling_ratio = 1 + +# This option should be enabled if you are using Juniper with mirroring of the first X bytesof packet: maximum-packet-length 110; +netmap_read_packet_length_from_ip_header = off + +# Pcap mode, very slow and thus not suitable for production +pcap = off +# Netflow capture method with v5, v9 and IPFIX support +netflow = {{ netflow_on }} +# sFLOW capture suitable for switches +sflow = off + +# PF_RING configuration +# If you have a license for PF_RING ZC, enable this mode and it might achieve wire speed for10GE +enable_pf_ring_zc_mode = off + +# Configuration for netmap, mirror, pcap modes +# For pcap and PF_RING we could specify "any" +# For netmap and PF_RING we could specify multiple interfaces separated by comma +interfaces = eth3,eth4 + +# We use average values for traffic speed to certain IP and we calculate average over this time slice +average_calculation_time = 5 + +# We use average values for traffic speed for subnet and we calculate average over this timeslice +average_calculation_time_for_subnets = 5 + +# Delay between traffic recalculation attempts +speed_calculation_delay = 1 + +# Netflow configuration + +# it's possible to specify multiple ports here, using commas as delimiter +netflow_port = {{ netflow_port }} +netflow_host = 0.0.0.0 + +# To bind to all interfaces for all protocols: not possible yet +# To bind to all interfaces for a specific protocol: :: or 0.0.0.0 +# To bind to localhost for a specific protocol: ::1 or 127.0.0.1 + +# Netflow v9 and IPFIX agents use different and very complex approaches for notifying about sample ratio +# Here you could specify a sampling ratio for all this agents +# For NetFLOW v5 we extract sampling ratio from packets directely and this option not used +netflow_sampling_ratio = 1 + +# sFlow configuration + +# It's possible to specify multiple ports here, using commas as delimiter +sflow_port = 6343 +# sflow_port = 6343,6344 +sflow_host = 0.0.0.0 + +# Some vendors may lie about full packet length in sFlow packet. To avoid this issue we can switch to using IP packet length from parsed header +sflow_read_packet_length_from_ip_header = off + + +### +### Actions when attack detected +### + +# This script executed for ban, unban and attack detail collection +notify_script_path = /usr/local/bin/notify_about_attack.sh + +# pass attack details to notify_script via stdin +# Pass details only in case of "ban" call +# No details will be passed for "unban" call +notify_script_pass_details = on + +# collect a full dump of the attack with full payload in pcap compatible format +collect_attack_pcap_dumps = on + +# Execute Deep Packet Inspection on captured PCAP packets +process_pcap_attack_dumps_with_dpi = on + +# Save attack details to Redis +redis_enabled = off + +# Redis configuration +redis_port = 6379 +redis_host = 127.0.0.1 + +# specify a custom prefix here +redis_prefix = mydc1 + +# We could store attack information to MongoDB +mongodb_enabled = off +mongodb_host = localhost +mongodb_port = 27017 +mongodb_database_name = fastnetmon + +# announce blocked IPs with BGP protocol with ExaBGP +exabgp = off +exabgp_command_pipe = /var/run/exabgp.cmd +exabgp_community = 65001:666 + +# specify multiple communities with this syntax: +# exabgp_community = [65001:666 65001:777] + +# specify different communities for host and subnet announces +# exabgp_community_subnet = 65001:667 +# exabgp_community_host = 65001:668 + +exabgp_next_hop = 10.0.3.114 + +# In complex cases you could have both options enabled and announce host and subnet simultaneously + +# Announce /32 host itself with BGP +exabgp_announce_host = on + +# Announce origin subnet of IP address instead IP itself +exabgp_announce_whole_subnet = off + +# Announce Flow Spec rules when we could detect certain attack type +# Please we aware! Flow Spec announce triggered when we collect some details about attack, +# i.e. when we call attack_details script +# Please disable exabgp_announce_host and exabgp_announce_whole_subnet if you want to use this feature +# Please use ExaBGP v4 only (Git version), for more details: https://github.com/pavel-odintsov/fastnetmon/blob/master/docs/BGP_FLOW_SPEC.md +exabgp_flow_spec_announces = off + +# GoBGP intergation +gobgp = on + +# Configuration for IPv4 announces +gobgp_next_hop = 0.0.0.0 +gobgp_announce_host = on +gobgp_announce_whole_subnet = off + +gobgp_community_host = 65001:666 +gobgp_community_subnet = 65001:777 + +# Configuration for IPv6 announces +gobgp_next_hop_ipv6 = 100::1 +gobgp_announce_host_ipv6 = off +gobgp_announce_whole_subnet_ipv6 = off + +gobgp_community_host_ipv6 = 65001:666 +gobgp_community_subnet_ipv6 = 65001:777 + +# Graphite monitoring +# InfluxDB is also supported, please check our reference: +# https://github.com/pavel-odintsov/fastnetmon/blob/master/docs/INFLUXDB_INTEGRATION.md +graphite = off +# Please use only IP because domain names are not allowed here +graphite_host = 127.0.0.1 +graphite_port = 2003 + +# Default namespace for Graphite data +graphite_prefix = fastnetmon + +# Before using InfluxDB you need to create database using influx tool: +# create database fastnetmon + +# InfluxDB +influxdb = off +influxdb_host = 127.0.0.1 +influxdb_port = 8086 +influxdb_database = fastnetmon + +# InfluxDB auth +influxdb_auth = off +influxdb_user = fastnetmon +influxdb_password = secure + +# Add local IP addresses and aliases to monitoring list +# Works only for Linux +monitor_local_ip_addresses = on + +# Add IP addresses for OpenVZ / Virtuozzo VEs to network monitoring list +monitor_openvz_vps_ip_addresses = off + +# Create group of hosts with non-standard thresholds +# You should create this group before (in configuration file) specifying any limits +# hostgroup = my_hosts:10.10.10.221/32,10.10.10.222/32 + +# Configure this group +my_hosts_enable_ban = off + +my_hosts_ban_for_pps = off +my_hosts_ban_for_bandwidth = off +my_hosts_ban_for_flows = off + +my_hosts_threshold_pps = 20000 +my_hosts_threshold_mbps = 1000 +my_hosts_threshold_flows = 3500 + +# Path to pid file for checking "if another copy of tool is running", it's useful when you run multiple instances of tool +pid_path = /var/run/fastnetmon.pid + +# Path to file where we store IPv4 traffic information for fastnetmon_client +cli_stats_file_path = /tmp/fastnetmon.dat + +# Path to file where we store IPv6 traffic information for fastnetmon_client +cli_stats_ipv6_file_path = /tmp/fastnetmon_ipv6.dat + +# Enable gRPC api (required for fastnetmon_api_client tool) +enable_api = on + +### +### Client configuration +### + +# Field used for sorting in client, valid values are: packets, bytes or flows +sort_parameter = packets +# How much IPs will be listed for incoming and outgoing channel eaters +max_ips_in_list = 7 diff --git a/roles/fastnetmon/vars/main.yml b/roles/fastnetmon/vars/main.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/roles/fastnetmon/vars/main.yml @@ -0,0 +1 @@ +--- diff --git a/roles/ndpi/README.md b/roles/ndpi/README.md new file mode 100644 index 0000000..77f743e --- /dev/null +++ b/roles/ndpi/README.md @@ -0,0 +1,9 @@ +# ansible-ndpi +this role builds nDPI from source on a fedora machine + +## License +GPLv3 + +## Author +wanderer@git.dotya.ml + diff --git a/roles/ndpi/defaults/main.yml b/roles/ndpi/defaults/main.yml new file mode 100644 index 0000000..84697bd --- /dev/null +++ b/roles/ndpi/defaults/main.yml @@ -0,0 +1,3 @@ +--- +ndpi_compat_version: 1.7 +ndpi_clone_dir: /tmp/ndpi diff --git a/roles/ndpi/tasks/main.yml b/roles/ndpi/tasks/main.yml new file mode 100644 index 0000000..8677788 --- /dev/null +++ b/roles/ndpi/tasks/main.yml @@ -0,0 +1,27 @@ +--- +- name: check if nDPI dir exists + stat: + path: "{{ndpi_clone_dir}}" + register: dir_present + +- name: get nDPI sources + shell: + cmd: git clone https://github.com/ntop/nDPI.git {{ndpi_clone_dir}} + when: dir_present.stat.exists == false + +- name: build and install nDPI + shell: + cmd: + cd {{ndpi_clone_dir}}; + git checkout {{ndpi_compat_version}}; + ./autogen.sh && + ./configure && + make && + make install && + make clean && + git switch - ; + ./autogen.sh && + ./configure && + make && + make install + chdir: "{{ndpi_clone_dir}}" diff --git a/roles/ndpi/vars/main.yml b/roles/ndpi/vars/main.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/roles/ndpi/vars/main.yml @@ -0,0 +1 @@ +--- diff --git a/roles/waitpls/README.md b/roles/waitpls/README.md new file mode 100644 index 0000000..b548c1f --- /dev/null +++ b/roles/waitpls/README.md @@ -0,0 +1,9 @@ +# ansible-waitpls +this role is used to wait until conditions for running are met + +## License +GPLv3 + +## Author +wanderer@git.dotya.ml + diff --git a/roles/waitpls/defaults/main.yml b/roles/waitpls/defaults/main.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/roles/waitpls/defaults/main.yml @@ -0,0 +1 @@ +--- diff --git a/roles/waitpls/tasks/main.yml b/roles/waitpls/tasks/main.yml new file mode 100644 index 0000000..470b26d --- /dev/null +++ b/roles/waitpls/tasks/main.yml @@ -0,0 +1,8 @@ +--- +- name: Wait until the file /tmp/gopls is present before continuing + delay: 10 + wait_for: + path: /.plsgo + timeout: 1200 + become: false + diff --git a/roles/waitpls/vars/main.yml b/roles/waitpls/vars/main.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/roles/waitpls/vars/main.yml @@ -0,0 +1 @@ +--- diff --git a/vms/main.tf b/vms/main.tf index 0d09864..f2c0432 100644 --- a/vms/main.tf +++ b/vms/main.tf @@ -58,6 +58,13 @@ variable "subnets" { variable "network_names" { type = list(string) } +variable "dhcp" { + type = list(bool) +} +variable "ssh_private_key" { + description = "the key to use for ansible stuff" + default = "~/.ssh/tf-ansible" +} # base OS image @@ -102,13 +109,13 @@ resource "libvirt_cloudinit_disk" "commoninit" { } resource "libvirt_network" "additional_networks" { - count = length(var.subnets) - name = var.network_names[count.index] - bridge = "br_${var.network_names[count.index]}" + count = length(var.subnets) + name = var.network_names[count.index] + # bridge = "br_${var.network_names[count.index]}" mode = "route" addresses = ["${var.subnets[count.index]}"] dhcp { - enabled = true + enabled = var.dhcp[count.index] } } @@ -145,6 +152,17 @@ resource "libvirt_domain" "defender-lab" { cloudinit = libvirt_cloudinit_disk.commoninit[each.value.name].id + provisioner "local-exec" { + command = < d_hosts + echo h_defender >> d_hosts + echo "[defender:vars]" >> d_hosts + ansible-playbook -u ansible --private-key ${var.ssh_private_key} -i d_hosts playbooks/defender.yml + EOF + } + + } diff --git a/vms/terraform.tfvars b/vms/terraform.tfvars index c7556ed..be6b66d 100644 --- a/vms/terraform.tfvars +++ b/vms/terraform.tfvars @@ -14,6 +14,7 @@ networkname = "default" # default==NAT subnets = ["10.16.4.0/24", "10.16.5.0/24", "10.16.6.0/24"] network_names = ["inner", "outer", "dmz"] +dhcp = [false, false, false] # host-specific settings