├── molecule └── default │ ├── verify.yml │ ├── converge.yml │ ├── molecule.yml │ ├── destroy.yml │ └── create.yml ├── Pipfile ├── meta └── main.yml ├── tasks ├── main.yml ├── firewall_addressess.yml ├── interfaces.yml ├── system.yml ├── hardening.yml ├── wireless.yml ├── vlan.yml └── manage_firewall_policy.yml ├── .ansible-lint ├── LICENSE ├── readme.md ├── defaults └── main.yml └── Pipfile.lock /molecule/default/verify.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This is an example playbook to execute Ansible tests. 3 | 4 | - name: Verify 5 | hosts: all 6 | gather_facts: false 7 | tasks: 8 | - name: Example assertion 9 | assert: 10 | that: true 11 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | 8 | [packages] 9 | molecule = "==3.1.5" 10 | ansible-lint = "==4.3.7" 11 | 12 | [packages.ansible] 13 | extras = [ "lint" ] 14 | version = "==2.10.3" 15 | 16 | [requires] 17 | python_version = "3" 18 | -------------------------------------------------------------------------------- /molecule/default/converge.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Converge 3 | hosts: all 4 | connection: network_cli 5 | gather_facts: false 6 | tasks: 7 | - name: demo run 8 | routeros_command: 9 | commands: 10 | - "/system identity print" 11 | register: output 12 | - debug: 13 | msg: "{{ output }}" 14 | - name: "Include ansible-mikrotik" 15 | include_role: 16 | name: "ansible-mikrotik" 17 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: Madnessy 4 | description: Manage / configure mikrotik devices 5 | license: MIT 6 | min_ansible_version: 2.7 7 | platforms: 8 | - name: RouterOs 9 | versions: 10 | - 6.44.3 11 | galaxy_tags: 12 | - mikrotik 13 | - routeros 14 | - networking 15 | dependencies: [] 16 | # List your role dependencies here, one per line. Be sure to remove the '[]' above, 17 | # if you add dependencies to this list. 18 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | - include: system.yml 2 | - include: interfaces.yml 3 | - include: wireless.yml 4 | when: manage_wireless_interface 5 | - include: vlan.yml 6 | - include: hardening.yml 7 | #- include: vpn.yml 8 | # when: manage_vpn 9 | - include: firewall_addressess.yml 10 | when: manage_firewall 11 | # Manage the firewall policies 12 | - name: Create the policies 13 | include_tasks: manage_firewall_policy.yml 14 | with_list: "{{ firewall_policies | dictsort }}" 15 | loop_control: 16 | loop_var: firewall_policies_item 17 | when: manage_firewall 18 | -------------------------------------------------------------------------------- /tasks/firewall_addressess.yml: -------------------------------------------------------------------------------- 1 | - name: Add adresses to lists 2 | routeros_command: 3 | commands: "/ip firewall address-list {{ item.1.action | default ('add') }} address={{ item.1.address }} comment=\"{{ item.1.comment }}\" disabled={{ item.1.disabled }} list={{ item.0.list }}" 4 | with_subelements: 5 | - "{{ firewall_address }}" 6 | - entrys 7 | 8 | #- name: Add adresses without list 9 | # routeros_command: 10 | # commands: "/ip firewall address-list {{ item.value.action | default ('add') }} address={{ item.key }} comment={{ item.value.comment }} disabled={{ item.value.disabled }}" 11 | # with_dict: "{{ firewall_address }}" 12 | # when: item.value.list is undefined 13 | -------------------------------------------------------------------------------- /molecule/default/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependency: 3 | name: galaxy 4 | driver: 5 | name: delegated 6 | options: 7 | managed: True 8 | ansible_connection_options: 9 | ansible_connection: network_cli 10 | lint: ansible-lint 11 | platforms: 12 | - name: rb4011 13 | mikrotik_version: 6.46.8 14 | user: admin 15 | serial_port: 2223 16 | ssh_fwd_port: 2222 17 | groups: 18 | - routeros 19 | provisioner: 20 | name: ansible 21 | log: true 22 | config_options: 23 | paramiko_connection: 24 | pty: false 25 | diff: 26 | always: true 27 | lint: 28 | name: ansible-lint 29 | inventory: 30 | host_vars: 31 | rb4011: 32 | manage_wireless_interface: false 33 | group_vars: 34 | routeros: 35 | ansible_network_os: routeros 36 | verifier: 37 | name: ansible 38 | -------------------------------------------------------------------------------- /.ansible-lint: -------------------------------------------------------------------------------- 1 | 2 | skip_list: [] 3 | 4 | warn_list: # or 'skip_list' to silence them completely │ 5 | - '106' # Role name {} does not match ``^[a-z][a-z0-9_]+$`` pattern │ 6 | - '204' # Lines should be no longer than 160 chars │ 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Madnessy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tasks/interfaces.yml: -------------------------------------------------------------------------------- 1 | - name: disable interfaces 2 | routeros_command: 3 | commands: 4 | - "/interface set {{ item }} disabled=yes" 5 | with_items: 6 | - "{{ disabled_interfaces }}" 7 | when: 8 | - disabled_interfaces is defined 9 | - disabled_interfaces is iterable 10 | 11 | - name: remove interfaces which will become bonds from bridge 12 | routeros_command: 13 | commands: 14 | - "/interface bridge port remove number=[ find interface={{ item }} ] " 15 | with_items: 16 | - "{{ interface_bond_slaves }}" 17 | when: 18 | - 'interface_bond_slaves is defined' 19 | 20 | - name: create 802.3ad bonds 21 | routeros_command: 22 | commands: 23 | - "/interface bonding add mode={{ item.value.mode }} name={{ item.key }} slaves={{ item.value.interfaces }}" 24 | - "/interface bridge port add bridge=bridge interface={{ item.key }}" 25 | with_dict: "{{ interface_bonds }}" 26 | when: 27 | - 'interface_bonds is defined' 28 | - ' item.value.mode == "802.3ad"' 29 | 30 | - name: create balance-xor bonds 31 | routeros_command: 32 | commands: 33 | - "/interface bonding add link-monitoring={{item.value.monitoring_mode| default ('mii')}} mode={{ item.value.mode }} name={{ item.key }} slaves={{ item.value.interfaces }}" 34 | - "/interface bridge port add bridge=bridge interface={{ item.key }}" 35 | with_dict: "{{ interface_bonds }}" 36 | when: 37 | - 'interface_bonds is defined' 38 | - ' item.value.mode == "balance-xor"' 39 | 40 | - name: create interfaces lists 41 | routeros_command: 42 | commands: "/interface list add name={{ item.name }} comment=\"{{ item.comment }}\"" 43 | with_items: "{{ interface_lists }}" 44 | when: interface_lists is defined 45 | 46 | - name: add interface to interface lists 47 | routeros_command: 48 | commands: "/interface list member add interface={{ item.1 }} list={{ item.0.name }}" 49 | with_subelements: 50 | - "{{ interface_lists }}" 51 | - interfaces 52 | when: interface_lists is defined 53 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## disclaimer : 2 | This playbook is all but done 3 | I made this for my own home situation, feel free to make additions , improvements etc 4 | This playbook has been made with RouterOs version 6.44.3 5 | 6 | ## how to use : 7 | 8 | set this in your ansible cfg : 9 | ``` 10 | [paramiko_connection] 11 | pty=False 12 | ``` 13 | 14 | Set this in your hostvars: 15 | ``` 16 | ansible_network_os: routeros 17 | ``` 18 | 19 | And then copy the vars (easiest way) : 20 | Just copy the defaults file (defaults/main.yml) to your hostvars dir and rename original main.yml (in defaults/) to something that will not be processed 21 | 22 | Example playbook : 23 | ``` 24 | 25 | - hosts: hosts 26 | remote_user: admin 27 | connection: network_cli 28 | gather_facts: false 29 | roles: 30 | - ansible-mikrotik 31 | ``` 32 | 33 | ## what can this playbook actually do : 34 | 35 | ### hardening 36 | some basic hardening stuff that mikrotik advises to do 37 | 38 | ### firewall 39 | add policies , not removing 40 | 41 | ### interfaces 42 | create a 802.3ad bond or a balance-xor bond 43 | disable interfaces 44 | make interface lists 45 | 46 | ### vlans 47 | create vlans based on bridge filtering 48 | assign interfaces to the vlan (tagged / untagged ) 49 | assign networks / dhcp servers to the vlan 50 | 51 | ### wireless 52 | create a security profile (kind of basic) 53 | create a virtual wlan interface 54 | set the master vlan interface (and set channels and such) 55 | 56 | ### generic: 57 | add a backup script and a upgrade script (not tested if the scripts actually work) 58 | set ntp client 59 | 60 | ### vpn: 61 | still a todo 62 | 63 | #### other remarks : 64 | just take a look at the default file , this maybe explain some stuff i forgot 65 | 66 | ## todo's : 67 | 68 | rework bond creation , to static, will need a solution like the adding of firewall policies 69 | 70 | ## testing: 71 | 72 | > notes: 73 | * utilizing Pipenv for package management 74 | * running Molecule with custom QEMU VM creator and MikroTik RouterOs 75 | 76 | > example: 77 | ``` 78 | $ pipenv update 79 | $ pipenv shell 80 | $ molecule create 81 | $ molecule converge 82 | $ molecule destroy 83 | ``` 84 | 85 | ## license: 86 | MIT 87 | -------------------------------------------------------------------------------- /tasks/system.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: create backup script 3 | routeros_command: 4 | commands: 5 | - "/system scheduler add interval=1w name=backup on-event=\"system backup save name=today.backup\" policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon start-date=jun/11/2018 start-time=00:00:00" 6 | - /user group add name=ftp policy="ftp,read,sensitive,!local,!telnet,!ssh,!reboot,!write,!policy,!test,!winbox,!password,!web,!sniff,!api,!romon,!dude,!tikapp" 7 | - "/user add address={{ backup_src_ip }} group=ftp name=ftp" 8 | - "/user set ftp password={{ backup_password }}" 9 | when: 10 | - backup_script | bool 11 | - backup_password is defined 12 | - backup_src_ip is defined 13 | 14 | - name: auto upgrade script 15 | routeros_command: 16 | commands: 17 | - "/system scheduler add interval=1w name=upgrade on-event=\"system package update check-for-updates once :delay 1s; :if ( [get status] = \\\"New version is available\\\") do={ install }\" policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon start-date=jun/12/2018 start-time=00:00:00" 18 | when: upgrade_script | bool 19 | 20 | - name: set ntp client (dns based) 21 | routeros_command: 22 | commands: 23 | - "/system ntp client set enabled=yes server-dns-names={{ ntp_client_dnsnames }}" 24 | when: 25 | - set_ntp_client_dns is defined 26 | - set_ntp_client_dns | bool 27 | 28 | - name: set ntp client (ip based) 29 | routeros_command: 30 | commands: 31 | - "/system ntp client set enabled=yes primary-ntp={{ ntp_client_ip1 }} secondary-ntp={{ ntp_client_ip2 }}" 32 | when: 33 | - set_ntp_client_ip is defined 34 | - set_ntp_client_ip| bool 35 | 36 | - name: set logging remote 37 | routeros_command: 38 | commands: 39 | - "/system logging action set number=[ find name=remote ] target=\"remote\" remote={{ system_logging_remote_ip }} remote-port={{ system_logging_remote_ip_port }} src-address=0.0.0.0 bsd-syslog=yes syslog-time-format=bsd-syslog syslog-facility=daemon syslog-severity=alert" 40 | when: 41 | - set_system_logging_remote is defined 42 | - set_system_logging_remote| bool 43 | 44 | - name: set logging 45 | routeros_command: 46 | commands: 47 | - "/system logging add action={{ item.0.action }} topics={{ item.1.name }}" 48 | with_subelements: 49 | - "{{ system_logging }}" 50 | - topics 51 | when: 52 | - set_system_logging is defined 53 | - set_system_logging| bool 54 | -------------------------------------------------------------------------------- /tasks/hardening.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: disable services 3 | routeros_command: 4 | commands: "/ip service disable {{ item }}" 5 | with_items: 6 | - "{{ disabled_services }}" 7 | 8 | - name: enabled services without ip restriction 9 | routeros_command: 10 | commands: "/ip service enable {{ item }}" 11 | with_items: 12 | - "{{ enabled_services }}" 13 | when: management_subnet is not defined 14 | 15 | - name: enabled services with ip restriction 16 | routeros_command: 17 | commands: 18 | - "/ip service enable {{ item }}" 19 | - "/ip service set {{ item }} address={{ management_subnet }}" 20 | with_items: 21 | - "{{ enabled_services }}" 22 | when: management_subnet is defined 23 | 24 | - name: disabled tools 25 | routeros_command: 26 | commands: "/tool mac-server mac-winbox set allowed-interface-list=none" 27 | when: disabled_tools_mac_winbox 28 | 29 | - name: disabled tools 30 | routeros_command: 31 | commands: "/tool mac-server ping set enabled=no" 32 | when: disabled_tools_mac_ping 33 | 34 | - name: disabled tools mac-server 35 | routeros_command: 36 | commands: /tool mac-server set allowed-interface-list=none 37 | when: disable_mac_telnet 38 | 39 | - name: disabled tools bandwidth-server 40 | routeros_command: 41 | commands: /tool bandwidth-server set enabled=no 42 | when: disable_bandwith_server 43 | 44 | - name: disable neighbor discovery 45 | routeros_command: 46 | commands: /ip neighbor discovery-settings set discover-interface-list=none 47 | when: disable_neighbor_discovery 48 | 49 | - name: disable packages 50 | routeros_command: 51 | commands: "/system package disable {{ item }}" 52 | with_items: "{{ disabled_packages }}" 53 | 54 | - name: disable dns caching 55 | routeros_command: 56 | commands: /ip dns set allow-remote-requests=no 57 | when: disable_dns_cache 58 | 59 | - name: disable caching proxy 60 | routeros_command: 61 | commands: /ip proxy set enabled=no 62 | when: disable_caching_proxy 63 | 64 | - name: disable caching proxy 65 | routeros_command: 66 | commands: /ip socks set enabled=no 67 | when: disable_socks_proxy 68 | 69 | - name: disable upnp 70 | routeros_command: 71 | commands: /ip upnp set enabled=no 72 | when: disable_upnp 73 | 74 | - name: disable lcd 75 | routeros_command: 76 | commands: /lcd set enabled=no 77 | when: disable_lcd 78 | 79 | - name: disable cloud 80 | routeros_command: 81 | commands: /ip cloud set ddns-enabled=no update-time=no 82 | when: disable_cloud 83 | 84 | - name: change ssh crypto to stronger 85 | routeros_command: 86 | commands: /ip ssh set allow-none-crypto=no strong-crypto=yes 87 | when: ssh_strong_crypto 88 | -------------------------------------------------------------------------------- /molecule/default/destroy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Destroy 3 | hosts: localhost 4 | connection: local 5 | gather_facts: false 6 | no_log: "{{ molecule_no_log }}" 7 | vars: 8 | image_store_dir: "/tmp/mikrotik_image" 9 | tasks: 10 | - name: Check PID files 11 | with_items: "{{ molecule_yml.platforms }}" 12 | stat: 13 | path: "{{ image_store_dir }}/{{ item.name }}.pid" 14 | register: pids 15 | 16 | - name: Export existing PID files 17 | set_fact: 18 | pid_files: "{{ pids.results | selectattr('stat.exists') | map(attribute='stat.path') | list }}" 19 | 20 | - when: pid_files|length > 0 21 | block: 22 | - name: Collect PIDs 23 | with_items: "{{ pid_files }}" 24 | command: 25 | cmd: "cat {{ item }}" 26 | register: loaded_pids 27 | 28 | - name: Export PIDs with file path 29 | set_fact: 30 | loaded_pids_with_fp: "{{ loaded_pids_with_fp|default([]) + [{ 'pid': item.stdout, 'fp': item.item }] }}" 31 | with_items: "{{ loaded_pids.results }}" 32 | 33 | - name: Destroy molecule instance(s) 34 | failed_when: 35 | - '(kills.rc != 0) and ("No such process" not in kills.stderr)' 36 | command: 37 | cmd: "kill {{ item.pid|int }}" 38 | register: kills 39 | with_items: "{{ loaded_pids_with_fp }}" 40 | 41 | - name: Wait for process kill 42 | wait_for: 43 | path: "/proc/{{ item.pid|int }}/status" 44 | state: absent 45 | with_items: "{{ loaded_pids_with_fp }}" 46 | ignore_errors: yes 47 | register: killed 48 | 49 | - name: Force kill stuck processes 50 | command: 51 | cmd: "kill -9 {{ item.pid|int }}" 52 | with_items: "{{ killed.results | select('failed') | map(attribute='item') | list }}" 53 | 54 | - name: Clean up left-over PID files 55 | file: 56 | path: "{{ item.fp }}" 57 | state: absent 58 | with_items: "{{ kills.results | select('changed') | selectattr('stderr', 'contains', 'No such process') | map(attribute='item') | list }}" 59 | 60 | - name: Check for remaining image files 61 | with_items: "{{ molecule_yml.platforms }}" 62 | vars: 63 | mikrotik_chr_runimage_qcow2: "chr-{{ item.mikrotik_version }}.{{ item.name }}.qcow2" 64 | stat: 65 | path: "{{ image_store_dir }}/{{ mikrotik_chr_runimage_qcow2 }}" 66 | register: images 67 | 68 | - name: Export remaining image files 69 | set_fact: 70 | image_files: "{{ images.results | selectattr('stat.exists') | map(attribute='stat.path') | list }}" 71 | 72 | - name: Cleanup remaining image files 73 | when: image_files|length > 0 74 | with_items: "{{ image_files }}" 75 | file: 76 | path: "{{ item }}" 77 | state: absent 78 | -------------------------------------------------------------------------------- /tasks/wireless.yml: -------------------------------------------------------------------------------- 1 | - name: set default securtiy profiles first 2 | routeros_command: 3 | commands: "/interface wireless security-profiles set [ find default=yes ] authentication-types={{item.value.auth_type}} mode=dynamic-keys supplicant-identity=MikroTik wpa-pre-shared-key={{item.value.password}} wpa2-pre-shared-key={{item.value.password}} unicast-ciphers=aes-ccm group-ciphers=aes-ccm" 4 | when: item.value.default_profile|bool 5 | with_dict: "{{ wireless_profile }}" 6 | 7 | - name: set additional securtiy profiles 8 | routeros_command: 9 | commands: "/interface wireless security-profiles add name={{ item.key }} authentication-types={{item.value.auth_type}} mode=dynamic-keys supplicant-identity=MikroTik wpa-pre-shared-key={{item.value.password}} wpa2-pre-shared-key={{item.value.password}} unicast-ciphers=aes-ccm group-ciphers=aes-ccm" 10 | when: not item.value.default_profile|bool 11 | with_dict: "{{ wireless_profile }}" 12 | 13 | 14 | - name: set default wireless interfaces with vlan 15 | routeros_command: 16 | commands: "/interface wireless set [ find default-name={{item.key}} ] band={{item.value.band}} channel-width={{item.value.channel_width}} disabled=no distance=indoors frequency={{item.value.frequency }} mode={{item.value.mode}} ssid={{item.value.ssid}} vlan-id={{item.value.vlan}} vlan-mode={{item.value.vlan_mode}} wds-default-bridge=bridge wireless-protocol=802.11 security-profile={{item.value.security_profile}}" 17 | when: 18 | - item.value.default_interface|bool 19 | - item.value.vlan is defined 20 | with_dict: "{{ wireless_interface }}" 21 | 22 | - name: set default wireless interfaces without vlan 23 | routeros_command: 24 | commands: "/interface wireless set [ find default-name={{item.key}} ] band={{item.value.band}} channel-width={{item.value.channel_width}} disabled=no distance=indoors frequency={{item.value.frequency }} mode={{item.value.mode}} ssid={{item.value.ssid}} wds-default-bridge=bridge wireless-protocol=802.11 security-profile={{item.value.security_profile}}" 25 | when: 26 | - item.value.default_interface|bool 27 | - item.value.vlan is undefined 28 | with_dict: "{{ wireless_interface }}" 29 | 30 | - name: add interfaces with vlan 31 | routeros_command: 32 | commands: 33 | - "/interface wireless add disabled=no master-interface={{item.value.master_interface}} name={{item.key}} ssid={{item.value.ssid}} vlan-id={{item.value.vlan}} vlan-mode={{item.value.vlan_mode}} wds-default-bridge=bridge wps-mode=disabled security-profile={{item.value.security_profile}}" 34 | - "/interface bridge port add bridge=bridge interface={{ item.key }}" 35 | when: 36 | - not item.value.default_interface|bool 37 | - item.value.vlan is defined 38 | with_dict: "{{ wireless_interface }}" 39 | 40 | - name: add interfaces without vlan 41 | routeros_command: 42 | commands: 43 | - "/interface wireless add disabled=no master-interface={{item.value.master_interface}} name={{item.key}} ssid={{item.value.ssid}} wds-default-bridge=bridge wps-mode=disabled security-profile={{item.value.security_profile}}" 44 | - "/interface bridge port add bridge=bridge interface={{ item.key }}" 45 | when: 46 | - not item.value.default_interface|bool 47 | - item.value.vlan is undefined 48 | with_dict: "{{ wireless_interface }}" 49 | -------------------------------------------------------------------------------- /tasks/vlan.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: enable firewall for vlans 3 | routeros_command: 4 | commands: /interface bridge settings set use-ip-firewall=yes use-ip-firewall-for-vlan=yes 5 | when: firewall_vlan_enable 6 | 7 | - name: set vlan filtering on bridge 8 | routeros_command: 9 | commands: "/interface bridge set ingress-filtering=yes name=bridge vlan-filtering=yes numbers=[ find name=bridge ]" 10 | when: 'vlans is defined' 11 | 12 | - name: set pvid on untagged port 13 | routeros_command: 14 | commands: "/interface bridge port set numbers=[find interface={{item.1}} ] pvid={{item.0.id}}" 15 | loop: "{{ vlans | subelements('untagged_interfaces', skip_missing=True) }}" 16 | 17 | - name: create vlans 18 | routeros_command: 19 | commands: 20 | - "/interface vlan add interface=bridge name=VLAN-{{ item.key }} vlan-id={{ item.key }}" 21 | with_dict: "{{ vlans }}" 22 | 23 | - name: create vlans part 2 (with tagged and untagged) 24 | routeros_command: 25 | commands: 26 | - "/interface bridge vlan add bridge=bridge tagged={{ item.value.tagged_interfaces| join(',') }} untagged={{ item.value.untagged_interfaces| join(',') }} vlan-ids={{ item.key }}" 27 | with_dict: "{{ vlans }}" 28 | when: 29 | - item.value.untagged_interfaces is defined 30 | - item.value.tagged_interfaces is defined 31 | 32 | - name: create vlans part 2 (with tagged ) 33 | routeros_command: 34 | commands: 35 | - "/interface bridge vlan add bridge=bridge tagged={{ item.value.tagged_interfaces| join(',') }} vlan-ids={{ item.key }}" 36 | with_dict: "{{ vlans }}" 37 | when: 38 | - item.value.untagged_interfaces is undefined 39 | - item.value.tagged_interfaces is defined 40 | 41 | - name: create vlans part 2 (with untagged ) 42 | routeros_command: 43 | commands: 44 | - "/interface bridge vlan add bridge=bridge untagged={{ item.value.untagged_interfaces| join(',') }} vlan-ids={{ item.key }}" 45 | with_dict: "{{ vlans }}" 46 | when: 47 | - item.value.untagged_interfaces is defined 48 | - item.value.tagged_interfaces is undefined 49 | 50 | - name: create vlans part 4 51 | routeros_command: 52 | commands: 53 | - "/interface bridge port add bridge=bridge interface=VLAN-{{ item.key }} pvid={{ item.key }}" 54 | with_dict: "{{ vlans }}" 55 | 56 | - name: create vlans part 5 (set ip on vlan if you want) 57 | routeros_command: 58 | commands: 59 | - "/ip address add address={{ item.value.ip_address }}/{{ item.value.netmask }} comment=addr-vlan-{{ item.key }} interface=VLAN-{{ item.key }} network={{ item.value.network }}" 60 | with_dict: "{{ vlans }}" 61 | when: item.value.ip_address is defined 62 | 63 | - name: create vlans part 6 (set dhcp on vlan if you want) 64 | routeros_command: 65 | commands: 66 | - "/ip pool add name=dhcp-pool-vlan-{{ item.key }} ranges={{ item.value.dhcp_pool}}" 67 | - "/ip dhcp-server add address-pool=dhcp-pool-vlan-{{ item.key }} disabled=no interface=VLAN-{{ item.key }} name=dhcp-vlan-{{ item.key }}" 68 | - "/ip dhcp-server network add address={{ item.value.network }}/{{ item.value.netmask }} dns-server={{ item.value.dns }} gateway={{ item.value.ip_address }} netmask={{ item.value.netmask }} lease-time={{ item.value.leasetime | default ('3d') }}" 69 | with_dict: "{{ vlans }}" 70 | when: 71 | - item.value.dhcp_pool is defined 72 | - item.value.dns is defined 73 | -------------------------------------------------------------------------------- /tasks/manage_firewall_policy.yml: -------------------------------------------------------------------------------- 1 | - name: Set the l_env 2 | set_fact: 3 | l_fw_command: "/ip firewall filter {{ item.value.operation }} {% if item.value.action is defined %}action={{item.value.action}} {% endif %}{% if item.value.connection_bytes is defined %}connection-bytes={{item.value.connection_bytes}} {% endif %}{% if item.value.connection_limit is defined %}connection-limit={{item.value.connection_limit}} {% endif %}{% if item.value.connection_mark is defined %}connection-mark={{item.value.connection_mark}} {% endif %}{% if item.value.connection_nat_state is defined %}connection-nat-state={{item.value.connection_nat_state}} {% endif %}{% if item.value.connection_rate is defined %}connection-rate={{item.value.connection_rate}} {% endif %}{% if item.value.connection_state is defined %}connection-state={{item.value.connection_state}} {% endif %}{% if item.value.connection_type is defined %}connection-type={{item.value.connection_type}} {% endif %}{% if item.value.dscp is defined %}dscp={{item.value.dscp}} {% endif %}{% if item.value.dst_limit is defined %}dst-limit={{item.value.dst_limit}} {% endif %}{% if item.value.icmp_options is defined %}icmp-options={{item.value.icmp_options}} {% endif %}{% if item.value.in_interface_list is defined %}in-interface-list=\"{{item.value.in_interface_list}}\" {% endif %}{% if item.value.jump_target is defined %}jump-target={{item.value.jump_target}} {% endif %}{% if item.value.log_prefix is defined %}log-prefix=\"{{item.value.log_prefix}}\" {% endif %}{% if item.value.out_interface is defined %}out-interface={{item.value.out_interface}} {% endif %}{% if item.value.packet_size is defined %}packet-size={{item.value.packet_size}} {% endif %}{% if item.value.priority is defined %}priority={{item.value.priority}} {% endif %}{% if item.value.reject_with is defined %}reject-with={{item.value.reject_with}} {% endif %}{% if item.value.src_address_list is defined %}src-address-list=\"{{item.value.src_address_list}}\" {% endif %}{% if item.value.tcp_flags is defined %}tcp-flags={{item.value.tcp_flags}} {% endif %}{% if item.value.ttl is defined %}ttl={{item.value.ttl}} {% endif %}{% if item.value.address_list is defined %}address-list=\"{{item.value.address_list}}\" {% endif %}{% if item.value.content is defined %}content={{item.value.content}} {% endif %}{% if item.value.dst_address is defined %}dst-address={{item.value.dst_address}} {% endif %}{% if item.value.dst_port is defined %}dst-port={{item.value.dst_port}} {% endif %}{% if item.value.in_bridge_port is defined %}in-bridge-port={{item.value.in_bridge_port}} {% endif %}{% if item.value.ingress_priority is defined %}ingress-priority={{item.value.ingress_priority}} {% endif %}{% if item.value.layer7_protocol is defined %}layer7-protocol={{item.value.layer7_protocol}} {% endif %}{% if item.value.nth is defined %}nth={{item.value.nth}} {% endif %}{% if item.value.out_interface_list is defined %}out-interface-list=\"{{item.value.out_interface_list}}\" {% endif %}{% if item.value.per_connection_classifier is defined %}per-connection-classifier={{item.value.per_connection_classifier}} {% endif %}{% if item.value.protocol is defined %}protocol={{item.value.protocol}} {% endif %}{% if item.value.routing_mark is defined %}routing-mark={{item.value.routing_mark}} {% endif %}{% if item.value.src_address_type is defined %}src-address-type={{item.value.src_address_type}} {% endif %}{% if item.value.tcp_mss is defined %}tcp-mss={{item.value.tcp_mss}} {% endif %}{% if item.value.chain is defined %}chain={{item.value.chain}} {% endif %}{% if item.value.address_list_timeout is defined %}address-list-timeout={{item.value.address_list_timeout}} {% endif %}{% if item.value.copy_from is defined %}copy-from={{item.value.copy_from}} {% endif %}{% if item.value.dst_address_list is defined %}dst-address-list=\"{{item.value.dst_address_list}}\" {% endif %}{% if item.value.fragment is defined %}fragment={{item.value.fragment}} {% endif %}{% if item.value.in_bridge_port_list is defined %}in-bridge-port-list=\"{{item.value.in_bridge_port_list}}\" {% endif %}{% if item.value.ipsec_policy is defined %}ipsec-policy={{item.value.ipsec_policy}} {% endif %}{% if item.value.limit is defined %}limit={{item.value.limit}} {% endif %}{% if item.value.out_bridge_port is defined %}out-bridge-port={{item.value.out_bridge_port}} {% endif %}{% if item.value.p2p is defined %}p2p={{item.value.p2p}} {% endif %}{% if item.value.place_before is defined %}place-before={{item.value.place_before}} {% endif %}{% if item.value.psd is defined %}psd={{item.value.psd}} {% endif %}{% if item.value.routing_table is defined %}routing-table={{item.value.routing_table}} {% endif %}{% if item.value.src_mac_address is defined %}src-mac-address={{item.value.src_mac_address}} {% endif %}{% if item.value.time is defined %}time={{item.value.time}} {% endif %}{% if item.value.comment is defined %}comment=\"{{item.value.comment}}\" {% endif %}{% if item.value.disabled is defined %}disabled={{item.value.disabled}} {% endif %}{% if item.value.dst_address_type is defined %}dst-address-type={{item.value.dst_address_type}} {% endif %}{% if item.value.hotspot is defined %}hotspot={{item.value.hotspot}} {% endif %}{% if item.value.in_interface is defined %}in-interface={{item.value.in_interface}} {% endif %}{% if item.value.ipv4_options is defined %}ipv4-options={{item.value.ipv4_options}} {% endif %}{% if item.value.log is defined %}log={{item.value.log}} {% endif %}{% if item.value.out_bridge_port_list is defined %}out-bridge-port-list=\"{{item.value.out_bridge_port_list}}\" {% endif %}{% if item.value.packet_mark is defined %}packet-mark={{item.value.packet_mark}} {% endif %}{% if item.value.port is defined %}port={{item.value.port}} {% endif %}{% if item.value.random is defined %}random={{item.value.random}} {% endif %}{% if item.value.src_address is defined %}src-address={{item.value.src_address}} {% endif %}{% if item.value.src_port is defined %}src-port={{item.value.src_port}} {% endif %}{% if item.value.tls_host is defined %}tls-host={{item.value.tls_host}} {% endif %} " 4 | with_dict: "{{ firewall_policies }}" 5 | when: item.key == firewall_policies_item.0 6 | 7 | - name: Add firewall policy 8 | routeros_command: 9 | commands: 10 | - "{{ l_fw_command }}" 11 | -------------------------------------------------------------------------------- /molecule/default/create.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Create 3 | hosts: localhost 4 | connection: local 5 | gather_facts: false 6 | no_log: "{{ molecule_no_log }}" 7 | vars: 8 | image_store_dir: "/tmp/mikrotik_image" 9 | tasks: 10 | - debug: 11 | var: molecule_yml 12 | - name: Prepare MikroTik image locally 13 | block: 14 | - name: Create local image directory 15 | file: 16 | state: directory 17 | path: "{{ image_store_dir }}" 18 | mode: 0755 19 | 20 | - name: Download images 21 | with_items: "{{ molecule_yml.platforms }}" 22 | vars: 23 | mikrotik_chr_baseimage: "chr-{{ item.mikrotik_version }}.img" 24 | mikrotik_chr_baseurl: "https://download.mikrotik.com/routeros/{{ item.mikrotik_version }}/{{ mikrotik_chr_baseimage }}.zip" 25 | unarchive: 26 | src: "{{ mikrotik_chr_baseurl }}" 27 | dest: "{{ image_store_dir }}" 28 | creates: "{{ image_store_dir }}/{{ mikrotik_chr_baseimage }}" 29 | remote_src: true 30 | 31 | - name: Convert to QCOW2 32 | with_items: "{{ molecule_yml.platforms }}" 33 | vars: 34 | mikrotik_chr_baseimage_source: "chr-{{ item.mikrotik_version }}.img" 35 | mikrotik_chr_baseimage_qcow2: "chr-{{ item.mikrotik_version }}.qcow2" 36 | command: 37 | creates: "{{ image_store_dir }}/{{ mikrotik_chr_baseimage_qcow2 }}" 38 | chdir: "{{ image_store_dir }}" 39 | cmd: >2 40 | qemu-img convert 41 | -f raw 42 | -O qcow2 43 | {{ mikrotik_chr_baseimage_source }} 44 | {{ mikrotik_chr_baseimage_qcow2 }} 45 | 46 | - name: Preparing MikroTik image snapshot 47 | with_items: "{{ molecule_yml.platforms }}" 48 | vars: 49 | mikrotik_chr_baseimage_qcow2: "chr-{{ item.mikrotik_version }}.qcow2" 50 | mikrotik_chr_runimage_qcow2: "chr-{{ item.mikrotik_version }}.{{ item.name }}.qcow2" 51 | command: 52 | creates: "{{ image_store_dir }}/{{ mikrotik_chr_runimage_qcow2 }}" 53 | chdir: "{{ image_store_dir }}" 54 | cmd: >2 55 | qemu-img create 56 | -f qcow2 57 | -F qcow2 58 | -b {{ mikrotik_chr_baseimage_qcow2 }} 59 | {{ mikrotik_chr_runimage_qcow2 }} 60 | 61 | - name: Prepare MikroTik machine locally 62 | block: 63 | - name: Start MikroTik machine 64 | with_items: "{{ molecule_yml.platforms }}" 65 | vars: 66 | mikrotik_chr_runimage_qcow2: "chr-{{ item.mikrotik_version }}.{{ item.name }}.qcow2" 67 | instance_mac_snip: "{{ (item.name|sha1|string)[:4]|upper }}" 68 | instance_mac_pref: "{{ '52:54:00:%s:%s'|format(instance_mac_snip[:2],instance_mac_snip[2:]) }}" 69 | command: 70 | chdir: "{{ image_store_dir }}" 71 | creates: "{{ image_store_dir }}/{{ item.name }}.pid" 72 | cmd: >2 73 | qemu-system-x86_64 74 | -nodefaults 75 | -nographic 76 | -M pc 77 | -m 128 78 | -smp cpus=2 79 | -hda {{ mikrotik_chr_runimage_qcow2 }} 80 | -boot c 81 | -vga none 82 | -serial mon:telnet:localhost:{{ item.serial_port|int }},server,nowait 83 | -nic user,id=n0,mac={{ instance_mac_pref }}:50,restrict=on,hostfwd=tcp:127.0.0.1:{{ item.ssh_fwd_port|int }}-:22 84 | -nic socket,id=n1,mac={{ instance_mac_pref }}:51,listen=:49231 85 | -nic socket,id=n2,mac={{ instance_mac_pref }}:52,listen=:49232 86 | -nic socket,id=n3,mac={{ instance_mac_pref }}:53,listen=:49233 87 | -nic socket,id=n4,mac={{ instance_mac_pref }}:54,listen=:49234 88 | -nic socket,id=n5,mac={{ instance_mac_pref }}:55,listen=:49235 89 | -nic socket,id=n6,mac={{ instance_mac_pref }}:56,listen=:49236 90 | -nic socket,id=n7,mac={{ instance_mac_pref }}:57,listen=:49237 91 | -pidfile {{ image_store_dir }}/{{ item.name }}.pid 92 | -daemonize 93 | register: server 94 | async: 7200 95 | poll: 0 96 | 97 | - name: Configure MikroTik machine base 98 | when: server.changed | default(false) | bool 99 | block: 100 | - name: Wait for instance(s) creation to complete 101 | async_status: 102 | jid: "{{ item.ansible_job_id }}" 103 | register: instance_jobs 104 | until: instance_jobs.finished 105 | retries: 300 106 | with_items: "{{ server.results }}" 107 | 108 | - name: Wait for qemu control telnet 109 | with_items: "{{ server.results }}" 110 | wait_for: 111 | host: localhost 112 | port: "{{ item.item.serial_port|int }}" 113 | 114 | - name: Send configuration commands to RouterOS serial 115 | with_items: "{{ server.results }}" 116 | vars: 117 | instance_mac_snip: "{{ (item.item.name|sha1|string)[:4]|upper }}" 118 | instance_mac_pref: "{{ '52:54:00:%s:%s'|format(instance_mac_snip[:2],instance_mac_snip[2:]) }}" 119 | telnet: 120 | host: localhost 121 | port: "{{ item.item.serial_port|int }}" 122 | user: "{{ item.item.user|default(admin) }}" 123 | password: "\n" 124 | login_prompt: 'MikroTik Login: ' 125 | password_prompt: 'Password: ' 126 | send_newline: true 127 | timeout: 20 128 | pause: 5 129 | prompts: 130 | - '[>|:]' 131 | command: 132 | - "n\r\n" 133 | - "\r\n" 134 | - "\r\n" 135 | - "/ip dhcp-client add interface=[/interface find mac-address~\"{{ instance_mac_pref }}:50\"] disabled=no\r\n" 136 | - "\r\n" 137 | - "\r\n" 138 | - "/quit\r\n" 139 | 140 | - name: Wait for Mikrotik control ssh 141 | when: server.changed | default(false) | bool 142 | with_items: "{{ server.results }}" 143 | wait_for: 144 | host: localhost 145 | port: "{{ item.item.ssh_fwd_port|int }}" 146 | 147 | - when: server.changed | default(false) | bool 148 | block: 149 | - name: Populate instance config dict 150 | set_fact: 151 | instance_conf_dict: { 152 | 'instance': "{{ item.item.name }}", 153 | 'address': "localhost", 154 | 'user': "{{ item.item.user }}", 155 | 'port': "{{ item.item.ssh_fwd_port }}", 156 | 'identity_file': "", } 157 | with_items: "{{ server.results }}" 158 | register: instance_config_dict 159 | 160 | - name: Convert instance config dict to a list 161 | set_fact: 162 | instance_conf: "{{ instance_config_dict.results | map(attribute='ansible_facts.instance_conf_dict') | list }}" 163 | 164 | - name: Dump instance config 165 | copy: 166 | content: | 167 | # Molecule managed 168 | 169 | {{ instance_conf | to_json | from_json | to_yaml }} 170 | dest: "{{ molecule_instance_config }}" 171 | mode: 0644 172 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_network_os: routeros 3 | # switches to enable or disable wireless / firewall 4 | manage_firewall: true 5 | magage_wireless_interface: true 6 | manage_vpn: true 7 | 8 | # hardening settings 9 | # based on mikrotik advice 10 | # for more info : https://wiki.mikrotik.com/wiki/Manual:Securing_Your_Router 11 | disabled_services: 12 | - telnet 13 | - api 14 | - api-ssl 15 | - winbox 16 | - ftp 17 | enabled_services: 18 | - ssh 19 | - www 20 | disabled_packages: 21 | - ipv6 22 | management_subnet: 192.168.88.0/24 23 | disabled_tools_mac_winbox: true 24 | disabled_tools_mac_ping: true 25 | disable_mac_telnet: true 26 | disable_bandwith_server: true 27 | disable_neighbor_discovery: true 28 | disable_packages: 29 | - ipv6 30 | disable_caching_proxy: true 31 | disable_socks_proxy: true 32 | disable_upnp: true 33 | disable_cloud: true 34 | ssh_strong_crypto: true 35 | disable_dns_cache: true 36 | disable_lcd: true 37 | set_system_logging_remote: true 38 | system_logging_remote_ip: 192.168.88.101 39 | system_logging_remote_ip_port: 514 40 | set_system_logging: true 41 | system_logging: 42 | - action: remote 43 | topics: 44 | - name: account 45 | - name: critical 46 | - name: dhcp 47 | - name: firewall 48 | - name: health 49 | - name: info 50 | - name: iscsi 51 | - name: manager 52 | - name: ntp 53 | - name: packet 54 | - name: read 55 | - name: ssh 56 | - name: store 57 | - name: ddns 58 | - name: dns 59 | - name: error 60 | - name: interface 61 | - name: l2tp 62 | - name: script 63 | - name: warning 64 | - name: wireless 65 | - name: backup 66 | - name: event 67 | - name: bridge 68 | - name: ipsec 69 | - name: ovpn 70 | - name: route 71 | - name: state 72 | - name: system 73 | - name: write 74 | # disabled_interfaces: 75 | # - ether4 76 | firewall_vlan_enable: true 77 | backup_password: backup 78 | backup_src_ip: 192.168.88.1 79 | backup_script: true 80 | upgrade_script: true 81 | set_ntp_client_ip: false 82 | ntp_client_ip1: 83 | ntp_client_ip2: 84 | set_ntp_client_dns: true 85 | ntp_client_dnsnames: 0.nl.pool.ntp.org,1.nl.pool.ntp.org 86 | 87 | # firewall settings 88 | firewall_address: 89 | - list: not_in_internet 90 | entrys: 91 | - address: 0.0.0.0/8 92 | comment: Self-Identification [RFC 3330] 93 | disabled: "no" 94 | - address: 10.0.0.0/8 95 | comment: "Self-Identification [RFC 3330]" 96 | disabled: "no" 97 | - address: 100.64.0.0/10 98 | comment: "RFC6890" 99 | disabled: "no" 100 | - address: 127.0.0.0/8 101 | comment: "Loopback [RFC 3330]" 102 | disabled: "no" 103 | - address: 169.254.0.0/16 104 | comment: "Link Local [RFC 3330]" 105 | disabled: "no" 106 | - address: 172.16.0.0/12 107 | comment: "Private[RFC 1918] - CLASS B" 108 | disabled: "no" 109 | - address: 192.0.0.0/24 110 | comment: "Reserved - IANA - TestNet1" 111 | disabled: "no" 112 | - address: 192.0.2.0/24 113 | comment: "Reserved - IANA - TestNet1" 114 | disabled: "no" 115 | - address: 192.88.99.0/24 116 | comment: "6to4 Relay Anycast [RFC 3068]" 117 | disabled: "no" 118 | - address: 192.168.0.0/24 119 | comment: "Private[RFC 1918]-CLASS-C" 120 | disabled: "no" 121 | - address: 198.18.0.0/15 122 | comment: "NIDB Testing" 123 | disabled: "no" 124 | - address: 198.51.100.0/24 125 | comment: "Reserved - IANA - TestNet2" 126 | disabled: "no" 127 | - address: 203.0.113.0/24 128 | comment: "Reserved - IANA - TestNet3" 129 | disabled: "no" 130 | - address: 224.0.0.0/4 131 | comment: "MC Class D IANA" 132 | disabled: "no" 133 | - address: 240.0.0.0/4 134 | comment: "RFC6890" 135 | disabled: "no" 136 | - list: adminaccess 137 | entrys: 138 | - address: 192.168.88.0/24 139 | comment: "Allow lan to admin interface" 140 | disabled: "no" 141 | 142 | # Used these names so we can add the policies in order 143 | firewall_policies: 144 | aaaa: 145 | operation: add 146 | action: fasttrack-connection 147 | chain: forward 148 | comment: FastTrack 149 | connection_state: established,related 150 | baaa: 151 | operation: add 152 | action: accept 153 | chain: forward 154 | comment: "Established, Related" 155 | connection_state: established,related 156 | caaa: 157 | operation: add 158 | action: drop 159 | chain: forward 160 | comment: "Drop invalid" 161 | connection_state: invalid 162 | log: "yes" 163 | log_prefix: invalid 164 | daaa: 165 | operation: add 166 | action: log 167 | # action: drop 168 | chain: forward 169 | comment: "Drop tries to reach not public addresses from LAN" 170 | dst_address_list: not_in_internet 171 | in_interface: bridge1 172 | log: "yes" 173 | log_prefix: "!public_from_LAN" 174 | out_interface: "!bridge1" 175 | eaaa: 176 | operation: add 177 | action: drop 178 | chain: forward 179 | comment: "Drop incoming packets that are not NATted" 180 | connection_nat_state: "!dstnat" 181 | connection_state: new 182 | in_interface: ether1 183 | log: "yes" 184 | log_prefix: "!NAT" 185 | faaa: 186 | operation: add 187 | action: drop 188 | chain: forward 189 | comment: "Drop incoming from internet which is not public IP" 190 | in_interface: ether1 191 | log: "yes" 192 | log_prefix: "!public" 193 | src_address_list: not_in_internet 194 | gaaa: 195 | operation: add 196 | action: drop 197 | chain: forward 198 | comment: "Drop packets from LAN that do not have LAN IP" 199 | in_interface: bridge1 200 | log: "yes" 201 | log_prefix: LAN_!LAN 202 | src_address: "!192.168.150.0/24" 203 | haaa: 204 | operation: add 205 | action: accept 206 | chain: input 207 | comment: "Accept established,related" 208 | connection_state: established,related 209 | iaaa: 210 | operation: add 211 | action: log 212 | # action: drop 213 | chain: input 214 | comment: "Drop invalid" 215 | connection_state: invalid 216 | jaaa: 217 | operation: add 218 | action: log 219 | # action: drop 220 | chain: input 221 | comment: "Drop all not coming from LAN" 222 | in_interface_list: "!LAN" 223 | kaaa: 224 | operation: add 225 | action: accept 226 | chain: input 227 | comment: "Accept ICMP" 228 | protocol: icmp 229 | laaa: 230 | operation: add 231 | action: accept 232 | chain: input 233 | comment: "Allow ADMIN to Router" 234 | in_interface_list: LAN 235 | src_address_list: adminaccess 236 | maaa: 237 | operation: add 238 | action: accept 239 | chain: input 240 | comment: "Allow LAN DNS queries_UDP" 241 | dst_port: 53 242 | in_interface_list: LAN 243 | protocol: udp 244 | naaa: 245 | operation: add 246 | action: accept 247 | chain: input 248 | comment: "Allow LAN DNS queries TCP" 249 | dst_port: 53 250 | in_interface_list: LAN 251 | protocol: tcp 252 | oaaa: 253 | operation: add 254 | action: drop 255 | chain: input 256 | comment: "Deny WAN DNS queries UDP" 257 | dst_port: 53 258 | in_interface_list: WAN 259 | log: "yes" 260 | protocol: udp 261 | paaa: 262 | operation: add 263 | action: drop 264 | chain: input 265 | comment: "Deny WAN DNS queries_TCP" 266 | dst_port: 53 267 | in_interface_list: WAN 268 | protocol: tcp 269 | saaa: 270 | operation: add 271 | action: drop 272 | chain: forward 273 | comment: "Drop invalid" 274 | connection_state: invalid 275 | taaa: 276 | operation: add 277 | action: drop 278 | chain: forward 279 | comment: "Drop all from WAN not DSTNATed" 280 | connection_nat_state: "!dstnat" 281 | connection_state: new 282 | in_interface_list: WAN 283 | uaaa: 284 | operation: add 285 | chain: input 286 | protocol: tcp 287 | psd: 21,3s,3,1 288 | action: add-src-to-address-list 289 | address_list: "port scanners" 290 | address_list_timeout: 2w 291 | comment: "Port scanners to list " 292 | disabled: "no" 293 | uaab: 294 | operation: add 295 | chain: input 296 | protocol: tcp 297 | tcp_flags: fin,!syn,!rst,!psh,!ack,!urg 298 | action: add-src-to-address-list 299 | address_list: "port scanners" 300 | address_list_timeout: 2w 301 | comment: "NMAP FIN Stealth scan" 302 | uaac: 303 | operation: add 304 | chain: input 305 | protocol: tcp 306 | tcp_flags: fin,syn 307 | action: add-src-to-address-list 308 | address_list: "port scanners" 309 | address_list_timeout: 2w 310 | comment: "SYN/FIN scan" 311 | uaad: 312 | operation: add 313 | chain: input 314 | protocol: tcp 315 | tcp_flags: syn,rst 316 | action: add-src-to-address-list 317 | address_list: "port scanners" 318 | address_list_timeout: 2w 319 | comment: "SYN/RST scan" 320 | uaae: 321 | operation: add 322 | chain: input 323 | protocol: tcp 324 | tcp_flags: fin,psh,urg,!syn,!rst,!ack 325 | action: add-src-to-address-list 326 | address_list: "port scanners" 327 | address_list_timeout: 2w 328 | comment: "FIN/PSH/URG scan" 329 | uaaf: 330 | operation: add 331 | chain: input 332 | protocol: tcp 333 | tcp_flags: fin,syn,rst,psh,ack,urg 334 | action: add-src-to-address-list 335 | address_list: "port scanners" 336 | address_list_timeout: 2w 337 | comment: "ALL/ALL scan" 338 | uaag: 339 | operation: add 340 | chain: input 341 | protocol: tcp 342 | tcp_flags: "!fin,!syn,!rst,!psh,!ack,!urg" 343 | action: add-src-to-address-list 344 | address_list: "port scanners" 345 | address_list_timeout: 2w 346 | comment: "NMAP NULL scan" 347 | uaah: 348 | operation: add 349 | chain: input 350 | src_address_list: "port scanners" 351 | action: drop 352 | comment: "dropping port scanners" 353 | disabled: "no" 354 | zzzz: 355 | operation: add 356 | action: log 357 | # action: drop 358 | chain: input 359 | comment: "DROP ALL ELSE" 360 | log_prefix: "INPUT DROP ALL" 361 | 362 | # i know , fugly solution but a non-existing dict will break a loop. 363 | interface_bond_slaves: 364 | - ether2 365 | - ether3 366 | - ether9 367 | - ether10 368 | 369 | interface_bonds: 370 | bond-1: 371 | mode: 802.3ad 372 | interfaces: ether4,ether5 373 | bond-2: 374 | mode: balance-xor 375 | arp_monitor_ip: 192.168.88.10 376 | interfaces: ether3 377 | 378 | wireless_profile: 379 | default: 380 | default_profile: true 381 | auth_type: wpa2-psk 382 | password: hottentottententoonstelling 383 | extra_profile: 384 | default_profile: false 385 | auth_type: wpa2-psk 386 | password: abracadabrakofschiptitanic 387 | 388 | wireless_interface: 389 | wlan1: 390 | default_interface: true 391 | band: 2ghz-b/g/n 392 | channel_width: 20/40mhz-Ce 393 | frequency: 2442 394 | mode: ap-bridge 395 | ssid: blabla 396 | vlan: 20 397 | vlan_mode: use-tag 398 | security_profile: default 399 | extra_ssid: 400 | default_interface: false 401 | ssid: borkborkbork 402 | master_interface: wlan1 403 | security_profile: extra_profile 404 | 405 | # do not add slave ports for a bond to interface list , but only the bond interface 406 | interface_lists: 407 | - name: LAN 408 | comment: "Contains all lan interfaces" 409 | interfaces: 410 | - ether2 411 | - bond-1 412 | - bond-2 413 | - name: WAN 414 | comment: "Contains all wan interfaces" 415 | interfaces: 416 | - ether1 417 | 418 | vlans: 419 | - 10: 420 | untagged_interfaces: ether4,ether5 421 | tagged_interfaces: ether5,ether4 422 | network: 192.168.88.0 423 | netmask: 24 424 | ip_address: 192.168.88.1 425 | dns: 192.168.88.38 426 | dhcp_pool: 192.168.88.10-192.168.88.250 427 | - 20: 428 | untagged_interfaces: ether3 429 | network: 192.168.89.0 430 | netmask: 24 431 | ip_address: 192.168.89.1 432 | dns: 192.168.88.38 433 | dhcp_pool: 192.168.89.10-192.168.89.250 434 | leasetime: 1d 435 | - 30: 436 | tagged_interfaces: ether5,ether4 437 | - 40: 438 | tagged_interfaces: ether5,ether4 439 | network: 192.168.90.0 440 | ip_address: 192.168.90.1 441 | netmask: 24 442 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "2ba7160ffcbcc4f9dc6aabb15e996fd472edfd0b0ffc613ccc7ef1faf087c478" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "ansible": { 20 | "extras": [ 21 | "lint" 22 | ], 23 | "hashes": [ 24 | "sha256:eb1d08b9b98a60e90e7123a12f40770780f29f9d73168da55d449106a9f4d348" 25 | ], 26 | "index": "pypi", 27 | "version": "==2.10.3" 28 | }, 29 | "ansible-base": { 30 | "hashes": [ 31 | "sha256:33ae323923b841f3d822f355380ce7c92610440362efeed67b4b39db41e555af" 32 | ], 33 | "version": "==2.10.5" 34 | }, 35 | "ansible-lint": { 36 | "hashes": [ 37 | "sha256:1012fc3f5c4c0c58eece515860f19c34c5088faa5be412eec6fae5b45bda9c4f", 38 | "sha256:300e841f690b556a08d44902d6414283dc101079b27909e3a892f1cf1d10d7ff" 39 | ], 40 | "index": "pypi", 41 | "version": "==4.3.7" 42 | }, 43 | "arrow": { 44 | "hashes": [ 45 | "sha256:e098abbd9af3665aea81bdd6c869e93af4feb078e98468dd351c383af187aac5", 46 | "sha256:ff08d10cda1d36c68657d6ad20d74fbea493d980f8b2d45344e00d6ed2bf6ed4" 47 | ], 48 | "version": "==0.17.0" 49 | }, 50 | "bcrypt": { 51 | "hashes": [ 52 | "sha256:5b93c1726e50a93a033c36e5ca7fdcd29a5c7395af50a6892f5d9e7c6cfbfb29", 53 | "sha256:63d4e3ff96188e5898779b6057878fecf3f11cfe6ec3b313ea09955d587ec7a7", 54 | "sha256:81fec756feff5b6818ea7ab031205e1d323d8943d237303baca2c5f9c7846f34", 55 | "sha256:a67fb841b35c28a59cebed05fbd3e80eea26e6d75851f0574a9273c80f3e9b55", 56 | "sha256:c95d4cbebffafcdd28bd28bb4e25b31c50f6da605c81ffd9ad8a3d1b2ab7b1b6", 57 | "sha256:cd1ea2ff3038509ea95f687256c46b79f5fc382ad0aa3664d200047546d511d1", 58 | "sha256:cdcdcb3972027f83fe24a48b1e90ea4b584d35f1cc279d76de6fc4b13376239d" 59 | ], 60 | "version": "==3.2.0" 61 | }, 62 | "binaryornot": { 63 | "hashes": [ 64 | "sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061", 65 | "sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4" 66 | ], 67 | "version": "==0.4.4" 68 | }, 69 | "cerberus": { 70 | "hashes": [ 71 | "sha256:302e6694f206dd85cb63f13fd5025b31ab6d38c99c50c6d769f8fa0b0f299589" 72 | ], 73 | "version": "==1.3.2" 74 | }, 75 | "certifi": { 76 | "hashes": [ 77 | "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c", 78 | "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830" 79 | ], 80 | "version": "==2020.12.5" 81 | }, 82 | "cffi": { 83 | "hashes": [ 84 | "sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813", 85 | "sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06", 86 | "sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea", 87 | "sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee", 88 | "sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396", 89 | "sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73", 90 | "sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315", 91 | "sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1", 92 | "sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49", 93 | "sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892", 94 | "sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482", 95 | "sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058", 96 | "sha256:51182f8927c5af975fece87b1b369f722c570fe169f9880764b1ee3bca8347b5", 97 | "sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53", 98 | "sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045", 99 | "sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3", 100 | "sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5", 101 | "sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e", 102 | "sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c", 103 | "sha256:72d8d3ef52c208ee1c7b2e341f7d71c6fd3157138abf1a95166e6165dd5d4369", 104 | "sha256:8ae6299f6c68de06f136f1f9e69458eae58f1dacf10af5c17353eae03aa0d827", 105 | "sha256:8b198cec6c72df5289c05b05b8b0969819783f9418e0409865dac47288d2a053", 106 | "sha256:99cd03ae7988a93dd00bcd9d0b75e1f6c426063d6f03d2f90b89e29b25b82dfa", 107 | "sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4", 108 | "sha256:9de2e279153a443c656f2defd67769e6d1e4163952b3c622dcea5b08a6405322", 109 | "sha256:9e93e79c2551ff263400e1e4be085a1210e12073a31c2011dbbda14bda0c6132", 110 | "sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62", 111 | "sha256:a465da611f6fa124963b91bf432d960a555563efe4ed1cc403ba5077b15370aa", 112 | "sha256:ad17025d226ee5beec591b52800c11680fca3df50b8b29fe51d882576e039ee0", 113 | "sha256:afb29c1ba2e5a3736f1c301d9d0abe3ec8b86957d04ddfa9d7a6a42b9367e396", 114 | "sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e", 115 | "sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991", 116 | "sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6", 117 | "sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1", 118 | "sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406", 119 | "sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d", 120 | "sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c" 121 | ], 122 | "version": "==1.14.5" 123 | }, 124 | "chardet": { 125 | "hashes": [ 126 | "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", 127 | "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5" 128 | ], 129 | "version": "==4.0.0" 130 | }, 131 | "click": { 132 | "hashes": [ 133 | "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", 134 | "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" 135 | ], 136 | "version": "==7.1.2" 137 | }, 138 | "click-completion": { 139 | "hashes": [ 140 | "sha256:5bf816b81367e638a190b6e91b50779007d14301b3f9f3145d68e3cade7bce86" 141 | ], 142 | "version": "==0.5.2" 143 | }, 144 | "click-help-colors": { 145 | "hashes": [ 146 | "sha256:eb037a2dd95a9e20b3897c2b3ca57e7f6797f76a8d93f7eeedda7fcdcbc9b635", 147 | "sha256:f6c3d1fe86b07790e6ef0339f458196a8814de90946d876774ea4b4f30a5a539" 148 | ], 149 | "version": "==0.9" 150 | }, 151 | "colorama": { 152 | "hashes": [ 153 | "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b", 154 | "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2" 155 | ], 156 | "version": "==0.4.4" 157 | }, 158 | "commonmark": { 159 | "hashes": [ 160 | "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60", 161 | "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9" 162 | ], 163 | "version": "==0.9.1" 164 | }, 165 | "cookiecutter": { 166 | "hashes": [ 167 | "sha256:430eb882d028afb6102c084bab6cf41f6559a77ce9b18dc6802e3bc0cc5f4a30", 168 | "sha256:efb6b2d4780feda8908a873e38f0e61778c23f6a2ea58215723bcceb5b515dac" 169 | ], 170 | "version": "==1.7.2" 171 | }, 172 | "cryptography": { 173 | "hashes": [ 174 | "sha256:0d7b69674b738068fa6ffade5c962ecd14969690585aaca0a1b1fc9058938a72", 175 | "sha256:1bd0ccb0a1ed775cd7e2144fe46df9dc03eefd722bbcf587b3e0616ea4a81eff", 176 | "sha256:3c284fc1e504e88e51c428db9c9274f2da9f73fdf5d7e13a36b8ecb039af6e6c", 177 | "sha256:49570438e60f19243e7e0d504527dd5fe9b4b967b5a1ff21cc12b57602dd85d3", 178 | "sha256:541dd758ad49b45920dda3b5b48c968f8b2533d8981bcdb43002798d8f7a89ed", 179 | "sha256:5a60d3780149e13b7a6ff7ad6526b38846354d11a15e21068e57073e29e19bed", 180 | "sha256:7951a966613c4211b6612b0352f5bf29989955ee592c4a885d8c7d0f830d0433", 181 | "sha256:922f9602d67c15ade470c11d616f2b2364950602e370c76f0c94c94ae672742e", 182 | "sha256:a0f0b96c572fc9f25c3f4ddbf4688b9b38c69836713fb255f4a2715d93cbaf44", 183 | "sha256:a777c096a49d80f9d2979695b835b0f9c9edab73b59e4ceb51f19724dda887ed", 184 | "sha256:a9a4ac9648d39ce71c2f63fe7dc6db144b9fa567ddfc48b9fde1b54483d26042", 185 | "sha256:aa4969f24d536ae2268c902b2c3d62ab464b5a66bcb247630d208a79a8098e9b", 186 | "sha256:c7390f9b2119b2b43160abb34f63277a638504ef8df99f11cb52c1fda66a2e6f", 187 | "sha256:e18e6ab84dfb0ab997faf8cca25a86ff15dfea4027b986322026cc99e0a892da" 188 | ], 189 | "index": "pypi", 190 | "version": "==3.3.2" 191 | }, 192 | "distro": { 193 | "hashes": [ 194 | "sha256:0e58756ae38fbd8fc3020d54badb8eae17c5b9dcbed388b17bb55b8a5928df92", 195 | "sha256:df74eed763e18d10d0da624258524ae80486432cd17392d9c3d96f5e83cd2799" 196 | ], 197 | "version": "==1.5.0" 198 | }, 199 | "idna": { 200 | "hashes": [ 201 | "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", 202 | "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" 203 | ], 204 | "version": "==2.10" 205 | }, 206 | "jinja2": { 207 | "hashes": [ 208 | "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419", 209 | "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6" 210 | ], 211 | "version": "==2.11.3" 212 | }, 213 | "jinja2-time": { 214 | "hashes": [ 215 | "sha256:d14eaa4d315e7688daa4969f616f226614350c48730bfa1692d2caebd8c90d40", 216 | "sha256:d3eab6605e3ec8b7a0863df09cc1d23714908fa61aa6986a845c20ba488b4efa" 217 | ], 218 | "version": "==0.2.0" 219 | }, 220 | "markupsafe": { 221 | "hashes": [ 222 | "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", 223 | "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", 224 | "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", 225 | "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", 226 | "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42", 227 | "sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f", 228 | "sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39", 229 | "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", 230 | "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", 231 | "sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014", 232 | "sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f", 233 | "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", 234 | "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", 235 | "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", 236 | "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", 237 | "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b", 238 | "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", 239 | "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15", 240 | "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", 241 | "sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85", 242 | "sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1", 243 | "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", 244 | "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", 245 | "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", 246 | "sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850", 247 | "sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0", 248 | "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", 249 | "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", 250 | "sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb", 251 | "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", 252 | "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", 253 | "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", 254 | "sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1", 255 | "sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2", 256 | "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", 257 | "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", 258 | "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", 259 | "sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7", 260 | "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", 261 | "sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8", 262 | "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", 263 | "sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193", 264 | "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", 265 | "sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b", 266 | "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", 267 | "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2", 268 | "sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5", 269 | "sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c", 270 | "sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032", 271 | "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7", 272 | "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be", 273 | "sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621" 274 | ], 275 | "version": "==1.1.1" 276 | }, 277 | "molecule": { 278 | "hashes": [ 279 | "sha256:79e42e9b896e1b587fc28262185553f1796d898703559423d3ede647756db7e6", 280 | "sha256:fef66f223176508f47ccaa1f37371e64444ced302074a7fb6e07f601ee6af6e5" 281 | ], 282 | "index": "pypi", 283 | "version": "==3.1.5" 284 | }, 285 | "packaging": { 286 | "hashes": [ 287 | "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5", 288 | "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a" 289 | ], 290 | "version": "==20.9" 291 | }, 292 | "paramiko": { 293 | "hashes": [ 294 | "sha256:4f3e316fef2ac628b05097a637af35685183111d4bc1b5979bd397c2ab7b5898", 295 | "sha256:7f36f4ba2c0d81d219f4595e35f70d56cc94f9ac40a6acdf51d6ca210ce65035" 296 | ], 297 | "version": "==2.7.2" 298 | }, 299 | "pathspec": { 300 | "hashes": [ 301 | "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd", 302 | "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d" 303 | ], 304 | "version": "==0.8.1" 305 | }, 306 | "pexpect": { 307 | "hashes": [ 308 | "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937", 309 | "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c" 310 | ], 311 | "version": "==4.8.0" 312 | }, 313 | "pluggy": { 314 | "hashes": [ 315 | "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", 316 | "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" 317 | ], 318 | "version": "==0.13.1" 319 | }, 320 | "poyo": { 321 | "hashes": [ 322 | "sha256:3e2ca8e33fdc3c411cd101ca395668395dd5dc7ac775b8e809e3def9f9fe041a", 323 | "sha256:e26956aa780c45f011ca9886f044590e2d8fd8b61db7b1c1cf4e0869f48ed4dd" 324 | ], 325 | "version": "==0.5.0" 326 | }, 327 | "ptyprocess": { 328 | "hashes": [ 329 | "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", 330 | "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220" 331 | ], 332 | "version": "==0.7.0" 333 | }, 334 | "pycparser": { 335 | "hashes": [ 336 | "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0", 337 | "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705" 338 | ], 339 | "version": "==2.20" 340 | }, 341 | "pygments": { 342 | "hashes": [ 343 | "sha256:37a13ba168a02ac54cc5891a42b1caec333e59b66addb7fa633ea8a6d73445c0", 344 | "sha256:b21b072d0ccdf29297a82a2363359d99623597b8a265b8081760e4d0f7153c88" 345 | ], 346 | "version": "==2.8.0" 347 | }, 348 | "pynacl": { 349 | "hashes": [ 350 | "sha256:06cbb4d9b2c4bd3c8dc0d267416aaed79906e7b33f114ddbf0911969794b1cc4", 351 | "sha256:11335f09060af52c97137d4ac54285bcb7df0cef29014a1a4efe64ac065434c4", 352 | "sha256:2fe0fc5a2480361dcaf4e6e7cea00e078fcda07ba45f811b167e3f99e8cff574", 353 | "sha256:30f9b96db44e09b3304f9ea95079b1b7316b2b4f3744fe3aaecccd95d547063d", 354 | "sha256:4e10569f8cbed81cb7526ae137049759d2a8d57726d52c1a000a3ce366779634", 355 | "sha256:511d269ee845037b95c9781aa702f90ccc36036f95d0f31373a6a79bd8242e25", 356 | "sha256:537a7ccbea22905a0ab36ea58577b39d1fa9b1884869d173b5cf111f006f689f", 357 | "sha256:54e9a2c849c742006516ad56a88f5c74bf2ce92c9f67435187c3c5953b346505", 358 | "sha256:757250ddb3bff1eecd7e41e65f7f833a8405fede0194319f87899690624f2122", 359 | "sha256:7757ae33dae81c300487591c68790dfb5145c7d03324000433d9a2c141f82af7", 360 | "sha256:7c6092102219f59ff29788860ccb021e80fffd953920c4a8653889c029b2d420", 361 | "sha256:8122ba5f2a2169ca5da936b2e5a511740ffb73979381b4229d9188f6dcb22f1f", 362 | "sha256:9c4a7ea4fb81536c1b1f5cc44d54a296f96ae78c1ebd2311bd0b60be45a48d96", 363 | "sha256:c914f78da4953b33d4685e3cdc7ce63401247a21425c16a39760e282075ac4a6", 364 | "sha256:cd401ccbc2a249a47a3a1724c2918fcd04be1f7b54eb2a5a71ff915db0ac51c6", 365 | "sha256:d452a6746f0a7e11121e64625109bc4468fc3100452817001dbe018bb8b08514", 366 | "sha256:ea6841bc3a76fa4942ce00f3bda7d436fda21e2d91602b9e21b7ca9ecab8f3ff", 367 | "sha256:f8851ab9041756003119368c1e6cd0b9c631f46d686b3904b18c0139f4419f80" 368 | ], 369 | "version": "==1.4.0" 370 | }, 371 | "pyparsing": { 372 | "hashes": [ 373 | "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", 374 | "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" 375 | ], 376 | "version": "==2.4.7" 377 | }, 378 | "python-dateutil": { 379 | "hashes": [ 380 | "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", 381 | "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a" 382 | ], 383 | "version": "==2.8.1" 384 | }, 385 | "python-slugify": { 386 | "hashes": [ 387 | "sha256:69a517766e00c1268e5bbfc0d010a0a8508de0b18d30ad5a1ff357f8ae724270" 388 | ], 389 | "version": "==4.0.1" 390 | }, 391 | "pyyaml": { 392 | "hashes": [ 393 | "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf", 394 | "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696", 395 | "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393", 396 | "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77", 397 | "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922", 398 | "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5", 399 | "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8", 400 | "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10", 401 | "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc", 402 | "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018", 403 | "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e", 404 | "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253", 405 | "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183", 406 | "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb", 407 | "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185", 408 | "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db", 409 | "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46", 410 | "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b", 411 | "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63", 412 | "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df", 413 | "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc" 414 | ], 415 | "version": "==5.4.1" 416 | }, 417 | "requests": { 418 | "hashes": [ 419 | "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", 420 | "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e" 421 | ], 422 | "version": "==2.25.1" 423 | }, 424 | "rich": { 425 | "hashes": [ 426 | "sha256:a8ee22199562278d2f78148cacb2f9460ccac362cd4a40f705505b41daae60e0", 427 | "sha256:f8f08fdac6bd67dc2dd7fe976da702d748487aa9eb5d050c48b2321bc67ed659" 428 | ], 429 | "version": "==9.11.0" 430 | }, 431 | "ruamel.yaml": { 432 | "hashes": [ 433 | "sha256:012b9470a0ea06e4e44e99e7920277edf6b46eee0232a04487ea73a7386340a5", 434 | "sha256:076cc0bc34f1966d920a49f18b52b6ad559fbe656a0748e3535cf7b3f29ebf9e" 435 | ], 436 | "markers": "python_version >= '3.7'", 437 | "version": "==0.16.12" 438 | }, 439 | "selinux": { 440 | "hashes": [ 441 | "sha256:820adcf1b4451c9cc7759848797703263ba0eb6a4cad76d73548a9e0d57b7926", 442 | "sha256:d435f514e834e3fdc0941f6a29d086b80b2ea51b28112aee6254bd104ee42a74" 443 | ], 444 | "markers": "sys_platform == 'linux'", 445 | "version": "==0.2.1" 446 | }, 447 | "sh": { 448 | "hashes": [ 449 | "sha256:6f792e45b45d039b423081558904981e8ab49572b0c38009fcc65feaab06bcda", 450 | "sha256:97a3d2205e3c6a842d87ebbc9ae93acae5a352b1bc4609b428d0fd5bb9e286a3" 451 | ], 452 | "version": "==1.13.1" 453 | }, 454 | "shellingham": { 455 | "hashes": [ 456 | "sha256:4855c2458d6904829bd34c299f11fdeed7cfefbf8a2c522e4caea6cd76b3171e", 457 | "sha256:536b67a0697f2e4af32ab176c00a50ac2899c5a05e0d8e2dadac8e58888283f9" 458 | ], 459 | "version": "==1.4.0" 460 | }, 461 | "six": { 462 | "hashes": [ 463 | "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", 464 | "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" 465 | ], 466 | "version": "==1.15.0" 467 | }, 468 | "text-unidecode": { 469 | "hashes": [ 470 | "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8", 471 | "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93" 472 | ], 473 | "version": "==1.3" 474 | }, 475 | "tree-format": { 476 | "hashes": [ 477 | "sha256:a538523aa78ae7a4b10003b04f3e1b37708e0e089d99c9d3b9e1c71384c9a7f9", 478 | "sha256:b5056228dbedde1fb81b79f71fb0c23c98e9d365230df9b29af76e8d8003de11" 479 | ], 480 | "version": "==0.1.2" 481 | }, 482 | "typing-extensions": { 483 | "hashes": [ 484 | "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918", 485 | "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c", 486 | "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f" 487 | ], 488 | "version": "==3.7.4.3" 489 | }, 490 | "urllib3": { 491 | "hashes": [ 492 | "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80", 493 | "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73" 494 | ], 495 | "version": "==1.26.3" 496 | }, 497 | "yamllint": { 498 | "hashes": [ 499 | "sha256:8a5f8e442f49309eaf3e9d7232ce76f2fc8026f5c0c0b164b83f33fed1399637", 500 | "sha256:b0e4c89985c7f5f8451c2eb8c67d804d10ac13a4abe031cbf49bdf3465d01087" 501 | ], 502 | "version": "==1.26.0" 503 | } 504 | }, 505 | "develop": {} 506 | } 507 | --------------------------------------------------------------------------------